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

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:组合模式(优先推荐)

如果未来设备类型或运行环境的维度可能扩展,单一继承会导致类爆炸,此时用组合替代继承更灵活:

  1. 先定义运行环境的接口和实现,封装通用逻辑:
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("目标设备通用电源控制逻辑");
    }
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 07:30:21