C#8继承(含Override)结合默认接口实现的代码复用方案咨询
问题描述
我有如下继承结构:
顶层是抽象类
Device,派生出DeviceType1和DeviceType2两个抽象类;每个设备类型又分别派生出三个具体类:TargetWithTeststandDevX、TargetWithSimulationDevX、TargetWithTargetDevX(X为1或2)。
其中所有TargetWithTeststand相关的具体类存在通用代码,我希望实现代码复用。目前想到两个方案:
- 用独立静态类归集通用方法
- 用带默认方法的通用接口,但默认方法不支持重写
请问有没有更优的方案处理这类继承问题?
代码示例
using System; public class Program { public static void Main() { int deviceType = 1; // 该值从可修改的配置文件读取 Device device = null; switch (deviceType) { case 0: device = new TargetWithTeststandDev1(); break; case 1: device = new TargetWithSimulationDev2(); break; // [...] } device.ReadMotorSpeed(); device.UsePowerButton(); } } public abstract class Device { public virtual void UsePowerButton() { throw new NotImplementedException(); } public virtual void ReadMotorSpeed() { throw new NotImplementedException(); } } public abstract class DeviceType1 : Device { public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType1读取电机转速"); } } public abstract class DeviceType2 : Device { public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType2读取电机转速"); } } public sealed class TargetWithTeststandDev1 : DeviceType1 { public override void UsePowerButton() { Console.WriteLine("在测试台使用DeviceType1的电源按钮"); } } public sealed class TargetWithSimulationDev1 : DeviceType1 { public override void UsePowerButton() { Console.WriteLine("在测试台使用DeviceType1的电源按钮"); } } public sealed class TargetWithTargetDev1 : DeviceType1 { public override void UsePowerButton() { Console.WriteLine("在目标设备使用DeviceType1的电源按钮"); } } public sealed class TargetWithTeststandDev2 : DeviceType2 { public override void UsePowerButton() { Console.WriteLine("在仿真环境使用DeviceType2的电源按钮"); } } public sealed class TargetWithSimulationDev2 : DeviceType2 { public override void UsePowerButton() { Console.WriteLine("在仿真环境使用DeviceType2的电源按钮"); } } public sealed class TargetWithTargetDev2 : DeviceType2 { public override void UsePowerButton() { Console.WriteLine("在目标设备使用DeviceType2的电源按钮"); } }
解决方案
针对你的场景,推荐两种更优的方案,核心思路都是拆分维度,避免单一继承的局限性:
方案1:按运行环境新增抽象类(分层继承)
当前继承是按设备类型划分的,现在可以同时按运行环境(Teststand、Simulation、Target)新增一层抽象类,将同一环境的通用逻辑抽离到对应抽象类中:
// 按运行环境拆分的抽象类 public abstract class TeststandDevice : Device { public override void UsePowerButton() { Console.WriteLine("通用测试台电源按钮逻辑"); // 若不同设备类型有差异,可留虚方法让子类重写 // OnUsePowerButton(); } // protected virtual void OnUsePowerButton() {} } public abstract class SimulationDevice : Device { public override void UsePowerButton() { Console.WriteLine("通用仿真环境电源按钮逻辑"); } } public abstract class TargetDevice : Device { public override void UsePowerButton() { Console.WriteLine("通用目标设备电源按钮逻辑"); } } // 设备类型与运行环境结合 public sealed class TargetWithTeststandDev1 : TeststandDevice { public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType1读取电机转速"); } } public sealed class TargetWithTeststandDev2 : TeststandDevice { public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType2读取电机转速"); } } // 同理实现Simulation和Target的设备类
这种方案直接通过继承复用通用逻辑,同时保留子类重写的能力,符合你现有代码的继承习惯,逻辑清晰。
方案2:组合模式(优先推荐)
如果未来设备类型或运行环境的维度可能扩展,单一继承会导致类爆炸,此时用组合替代继承更灵活:
- 先定义运行环境的接口和实现,封装通用逻辑:
public interface IPowerControl { void UsePowerButton(); } public class TeststandPowerControl : IPowerControl { public void UsePowerButton() { Console.WriteLine("测试台通用电源控制逻辑"); } } public class SimulationPowerControl : IPowerControl { public void UsePowerButton() { Console.WriteLine("仿真环境通用电源控制逻辑"); } } public class TargetPowerControl : IPowerControl { public void UsePowerButton() { Console.WriteLine("目标设备通用电源控制逻辑"); } }
- 修改Device类,通过组合注入IPowerControl:
public abstract class Device { protected IPowerControl _powerControl; protected Device(IPowerControl powerControl) { _powerControl = powerControl; } public virtual void UsePowerButton() { _powerControl.UsePowerButton(); } public virtual void ReadMotorSpeed() { throw new NotImplementedException(); } } // 具体设备类 public sealed class TargetWithTeststandDev1 : Device { public TargetWithTeststandDev1() : base(new TeststandPowerControl()) { } public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType1读取电机转速"); } } public sealed class TargetWithSimulationDev2 : Device { public TargetWithSimulationDev2() : base(new SimulationPowerControl()) { } public override void ReadMotorSpeed() { Console.WriteLine("使用DeviceType2读取电机转速"); } }
这种方案的优势:
- 彻底解耦设备类型和运行环境的逻辑,新增维度时不需要创建大量子类
- 运行时可以动态切换IPowerControl的实现(比如从配置读取后注入不同实例)
- 符合依赖倒置原则,代码扩展性更强
对比现有方案
- 静态类:虽然能复用代码,但无法继承和重写,也无法和设备类的状态交互(如果需要访问设备内部属性)
- 接口默认方法:确实不支持重写,且接口不应承载具体逻辑,违反接口隔离原则
内容的提问来源于stack exchange,提问作者Langer
相关产品推荐
相关产品推荐

