如何拓展多态下的子类

多态是对象编程的基础。其中一个原则就是要将共用特性抽取到基类。但开发中需求总是会变:如果子类需要新增方法怎么办?难道依次修改基类和其他子类吗?

当然不是。应该遵守开闭原则(OCP),使用特化子类。

例如以下三个类是标准多态结构。

csharp 复制代码
// 接口
public interface ICommunication
{
    void Send(byte[] data);
}

// TCP 实现
public class TcpClientComm : ICommunication
{
    public void Send(byte[] data) { /* TCP 实现 */ }
}

// 串口实现
public class SerialPortComm : ICommunication
{
    public void Send(byte[] data) { /* 串口实现 */ }
}

如果 SerialPortComm 需要增加新方法怎么办?

答案是直接添加。但在调用时,将其转为子类 SerialPortComm 使用,如下图:

csharp 复制代码
// 实现特有的发送字符函数
public class SerialPortComm : ICommunication
{
    public void Send(byte[] data) { /* ... */ }
    public void SendString(string data) { /* 串口特有逻辑 */ }
}

// 调用
// C# 9.0 以上的模式匹配(最推荐)
public void ProcessCommand(ICommunication comm)
{
    // 通用部分:所有设备都发字节
    comm.Send(new byte[] { 0x01, 0x02 });

    // 特殊部分:仅当该设备"具备字符串能力"时才执行
    if (comm is IStringCommunication stringable) // 这里不转具体类,转的是扩展接口
    {
        stringable.SendString("AT+RESET");
    }
}

扩展 1

怎么避免在调用时写太多if...else... ?

答案是动态调度,好处是调用方(Main函数)一行代码都不用改。

csharp 复制代码
public class CommandProcessor
{
    // 针对 TCP 的默认处理(字节流)
    private void ExecuteInternal(ICommunication comm)
        => comm.Send(new byte[] { 0x00 });

    // 针对串口的特殊处理(重载)
    private void ExecuteInternal(SerialComm comm)
        => comm.SendString("Hello");

    // 对外暴露的唯一入口,利用 dynamic 自动分流
    public void Execute(ICommunication comm)
    {
        // 核心技巧:把 comm 转为 dynamic,编译器会推迟绑定
        // 运行时自动寻找参数类型最匹配的 ExecuteInternal
        ExecuteInternal((dynamic)comm);
    }
}

var processor = new CommandProcessor();
processor.Execute(new SerialComm()); // 输出:串口发字符串
processor.Execute(new TcpComm());    // 发送 0x00

扩展 2

怎么避免修改已有的子类?

为了符合开闭原则(OCP),可以使用适配器模式。将旧子类和新方法一起包装成一个新类来使用,如下:

csharp 复制代码
// 不修改 Serial 原有的类
public class SerialStringAdapter : IStringCommunication
{
    private readonly SerialPortComm _serial;
    public SerialStringAdapter(SerialPortComm serial) { _serial = serial; }

    public void Send(byte[] data)
    {
        _serial.Send(data);
    }

    public void SendString(string data)
    {
        // 内部转成字节调用原来的 Send
        _serial.Send(Encoding.UTF8.GetBytes(data));
    }
}
相关推荐
昭昭日月明8 小时前
AI 时代的《重构》
设计模式·架构
He BianGu11 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
?abc!11 小时前
(贪心)621. 任务调度器
java·前端·c#
开开心心就好14 小时前
电脑小说阅读器,支持朗读和自定义皮肤
服务器·开发语言·javascript·算法·pdf·c#·音视频
淡海水15 小时前
07-06-源码-.NET Core GC的极致优化技术
unity·架构·c#·.netcore·gc·1024程序员节
工一木子15 小时前
设计模式与生活③:你的早晨,是一套模板
设计模式
万化冥合16 小时前
怎么批量把 Word 转 PDF?
python·pdf·c#·word
是2的10次方啊17 小时前
设计模式与生活④:冰箱空了,早餐换个买法
设计模式
淡海水1 天前
07-02-源码-.NET Core GC分配路径
算法·unity·c#·.netcore·gc·1024程序员节
知守观1 天前
设计模式实战:从真实老项目中看标准模板方法与工厂的落地
java·spring·设计模式