You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在我的C#场景下解决多类继承引发的代码重复问题?

问题背景

我的控制器模拟器需要支持以下5种类型组合:

  • ControllerSimulator
  • MovingControllerSimulator
  • RegistersControllerSimulator
  • ControllerSimulator + RegistersControllerSimulator
  • MovingControllerSimulator + RegistersControllerSimulator

因为C#不支持多类继承,我把RegistersControllerSimulator改成了接口,然后创建了RegistersMovingControllerSimulator和RegistersNonMovingControllerSimulator两个抽象类,但这导致了代码重复。想应用组合模式,但不知道怎么调整现有设计。

原有代码结构

public abstract class ControllerSimulator
{
   protected virtual void OnTurningOn() { }
   public void TurnOn()
   { 
     ...
   }
   
   protected virtual void OnTurningOff() { }
   public void TurnOff()
   { 
     ...
   }

   // 更多基础方法
   ...
}

public abstract class MovingControllerSimulator : ControllerSimulator
{
   public virtual void Disable() { }

   public void SetMotionDuration(TimeSpan duration)
   {
       _motionDuration = duration;
   }

    protected void OnMoveStarted()
    {
       MoveStarted?.Invoke();
    }

    // 更多基础方法
    ...
}

public abstract class RegistersControllerSimulator : ControllerSimulator
{
   protected Dictionary<string, object> Registers;
   
   protected abstract void OnRegisterChanged(string regName, object regVal); 
   public void UpdateRegister(string regName, object regVal)
   {
      Registers[regName] = regVal;
      OnRegisterChanged(...);
   }

   // 更多基础方法
   ...
}

尝试的解决方案(存在代码重复)

我把RegistersControllerSimulator转为接口,然后创建两个继承不同基类的抽象类,但UpdateRegister和Registers字段的代码完全重复:

定义接口

interface IRegistersControllerSimulator
{
   void UpdateRegister(string regName, object regVal);
}

public abstract class RegistersMovingControllerSimulator : MovingControllerSimulator, IRegistersControllerSimulator
{
   protected Dictionary<string, object> Registers;
   
   protected abstract void OnRegisterChanged(string regName, object regVal); 
   public void UpdateRegister(string regName, object regVal)
   {
      Registers[regName] = regVal;
      OnRegisterChanged(...);
   }
}    

public abstract class RegistersNonMovingControllerSimulator : ControllerSimulator, IRegistersControllerSimulator
{
   protected Dictionary<string, object> Registers;
   
   protected abstract void OnRegisterChanged(string regName, object regVal); 
   public void UpdateRegister(string regName, object regVal)
   {
      Registers[regName] = regVal;
      OnRegisterChanged(...);
   }
}

具体实现类

public class Concrete_Registers_Moving_Controller : RegistersMovingControllerSimulator
{
    protected override void OnRegisterChanged(string regName, object regVal)
    {
        if (regName == "Move")
        {
           // 模拟移动
           OnMoveStarted();
           // 示例用Wait,实际不建议这么做
           Task.Delay(_motionDuration).Wait();
        }
    }

    public Task StartMoveAsync2()
    {
         ...
         OnMoveStarted();
         return Task.Delay(_motionDuration);
    }
}

public class Concrete_Registers_NonMoving_Controller : RegistersNonMovingControllerSimulator
{
   protected override void OnRegisterChanged(string regName, object regVal)
    {
        if (regName == "Move2")
        {
           ...
           // 模拟移动
           OnMoveStarted();
           // 示例用Wait,实际不建议这么做
           Task.Delay(_motionDuration).Wait();
        }
    }
}

public class Concrete_NonRegisters_Moving_Controller : MovingControllerSimulator
{
    public Task StartMoveAsync()
    {
         OnMoveStarted();
         return Task.Delay(_motionDuration);
    }
}

public class Concrete_NonRegisters_NonMoving_Controller : ControllerSimulator
{
}

使用示例

var controllerRegMove = new Concrete_Registers_Moving_Controller();
controllerRegMove.UpdateRegister(...);
controllerRegMove.SetMotionDuration(...);
controllerRegMove.StartMoveAsync2();

var controllerRegNonMove = new Concrete_Registers_NonMoving_Controller();
controllerRegNonMove.UpdateRegister(...);
controllerRegNonMove.SomeNonMoveMethod(...);

var controllerNonRegMove = new Concrete_NonRegisters_Moving_Controller();
controllerNonRegMove.SetMotionDuration(...);
controllerNonRegMove.StartMoveAsync();

var controllerNonRegNonMove = new Concrete_NonRegisters_NonMoving_Controller();
controllerNonRegNonMove.SomeNonMoveMethod2(...);

组合模式优化方案

核心思路是把寄存器功能抽成独立的服务类,让需要寄存器功能的控制器组合这个服务,而不是通过继承实现,彻底消除代码重复。

1. 提取寄存器核心逻辑到独立类

// 寄存器服务类,封装所有寄存器相关逻辑
public class RegisterService
{
    private readonly Dictionary<string, object> _registers = new();
    // 注册寄存器变更事件,让外部控制器处理逻辑
    public event Action<string, object> RegisterChanged;

    public void UpdateRegister(string regName, object regVal)
    {
        _registers[regName] = regVal;
        RegisterChanged?.Invoke(regName, regVal);
    }

    // 可以在这里添加其他寄存器相关公共方法,比如读取寄存器
    public object GetRegister(string regName)
    {
        return _registers.TryGetValue(regName, out var val) ? val : null;
    }
}

2. 保留原有控制器继承体系,通过组合引入寄存器功能

不需要再创建重复的抽象类,而是让需要寄存器功能的控制器直接持有RegisterService实例:

// 基础控制器不变
public abstract class ControllerSimulator
{
   protected virtual void OnTurningOn() { }
   public void TurnOn()
   { 
     ...
   }
   
   protected virtual void OnTurningOff() { }
   public void TurnOff()
   { 
     ...
   }

   // 更多基础方法
   ...
}

// 移动控制器不变
public abstract class MovingControllerSimulator : ControllerSimulator
{
   protected TimeSpan _motionDuration;
   public event Action MoveStarted;

   public virtual void Disable() { }

   public void SetMotionDuration(TimeSpan duration)
   {
       _motionDuration = duration;
   }

    protected void OnMoveStarted()
    {
       MoveStarted?.Invoke();
    }

    // 更多基础方法
    ...
}

// 带寄存器的移动控制器:组合RegisterService
public class Concrete_Registers_Moving_Controller : MovingControllerSimulator
{
    private readonly RegisterService _registerService;

    public Concrete_Registers_Moving_Controller()
    {
        _registerService = new RegisterService();
        // 订阅寄存器变更事件,处理业务逻辑
        _registerService.RegisterChanged += OnRegisterChanged;
    }

    // 实现寄存器更新方法,委托给服务类
    public void UpdateRegister(string regName, object regVal)
    {
        _registerService.UpdateRegister(regName, regVal);
    }

    private void OnRegisterChanged(string regName, object regVal)
    {
        if (regName == "Move")
        {
           OnMoveStarted();
           Task.Delay(_motionDuration).Wait();
        }
    }

    public Task StartMoveAsync2()
    {
         OnMoveStarted();
         return Task.Delay(_motionDuration);
    }
}

// 带寄存器的非移动控制器:组合RegisterService
public class Concrete_Registers_NonMoving_Controller : ControllerSimulator
{
    private readonly RegisterService _registerService;

    public Concrete_Registers_NonMoving_Controller()
    {
        _registerService = new RegisterService();
        _registerService.RegisterChanged += OnRegisterChanged;
    }

    public void UpdateRegister(string regName, object regVal)
    {
        _registerService.UpdateRegister(regName, regVal);
    }

    private void OnRegisterChanged(string regName, object regVal)
    {
        if (regName == "Move2")
        {
           // 这里原代码调用了OnMoveStarted,但非移动控制器没有这个方法,需根据实际业务调整
           // 示例仅保留原有逻辑结构
           Task.Delay(TimeSpan.FromSeconds(1)).Wait();
        }
    }

    public void SomeNonMoveMethod()
    {
        // 非移动控制器业务逻辑
    }
}

// 不带寄存器的移动控制器(无需修改)
public class Concrete_NonRegisters_Moving_Controller : MovingControllerSimulator
{
    public Task StartMoveAsync()
    {
         OnMoveStarted();
         return Task.Delay(_motionDuration);
    }
}

// 不带寄存器的非移动控制器(无需修改)
public class Concrete_NonRegisters_NonMoving_Controller : ControllerSimulator
{
    public void SomeNonMoveMethod2()
    {
        // 业务逻辑
    }
}

3. 使用方式不变

var controllerRegMove = new Concrete_Registers_Moving_Controller();
controllerRegMove.UpdateRegister("Move", true);
controllerRegMove.SetMotionDuration(TimeSpan.FromSeconds(2));
controllerRegMove.StartMoveAsync2();

var controllerRegNonMove = new Concrete_Registers_NonMoving_Controller();
controllerRegNonMove.UpdateRegister("Move2", true);
controllerRegNonMove.SomeNonMoveMethod();

var controllerNonRegMove = new Concrete_NonRegisters_Moving_Controller();
controllerNonRegMove.SetMotionDuration(TimeSpan.FromSeconds(2));
controllerNonRegMove.StartMoveAsync();

var controllerNonRegNonMove = new Concrete_NonRegisters_NonMoving_Controller();
controllerNonRegNonMove.SomeNonMoveMethod2();

优化优势

  1. 消除代码重复:寄存器的核心逻辑只在RegisterService中实现一次,所有需要的控制器直接复用
  2. 灵活性更高:可以随时给任意控制器添加寄存器功能,不需要修改继承体系
  3. 单一职责:控制器专注于自身业务(开关机、移动),寄存器逻辑由专门的服务类处理
  4. 易于扩展:后续如果需要添加新的寄存器相关功能,只需要修改RegisterService,所有依赖它的控制器自动受益

内容的提问来源于stack exchange,提问作者theateist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:34:58