如何在我的C#场景下解决多类继承引发的代码重复问题?
问题背景
我的控制器模拟器需要支持以下5种类型组合:
ControllerSimulatorMovingControllerSimulatorRegistersControllerSimulatorControllerSimulator+RegistersControllerSimulatorMovingControllerSimulator+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();
优化优势
- 消除代码重复:寄存器的核心逻辑只在
RegisterService中实现一次,所有需要的控制器直接复用 - 灵活性更高:可以随时给任意控制器添加寄存器功能,不需要修改继承体系
- 单一职责:控制器专注于自身业务(开关机、移动),寄存器逻辑由专门的服务类处理
- 易于扩展:后续如果需要添加新的寄存器相关功能,只需要修改
RegisterService,所有依赖它的控制器自动受益
内容的提问来源于stack exchange,提问作者theateist
相关产品推荐
相关产品推荐

