如何拓展多态下的子类

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

当然不是。应该遵守开闭原则(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));
    }
}
相关推荐
南一Nanyi7 小时前
依赖注入和控制反转
前端·设计模式·nestjs
EIP低代码平台7 小时前
EIP低代码平台-系统参数配置详解|落地三级等保+高灵活私有化部署方案
低代码·c#·权限·工作流·netcore
王莎莎-MinerU9 小时前
MCP 解决的是工具接入,科研 Agent 还缺的是科学证据接口标准化
开发语言·网络·人工智能·深度学习·pdf·c#·php
-银雾鸢尾-9 小时前
C#中Object类内的方法
开发语言·c#
geats人山人海12 小时前
c# 第九章 record
开发语言·c#
-银雾鸢尾-12 小时前
C#中的抽象类与抽象方法
开发语言·c#
jctech13 小时前
让「小程序」跑起真正的原生代码:ComboNative 多进程原生小程序运行时 · Alpha 首发
android·设计模式·架构
影寂ldy13 小时前
C# Task 进阶:WaitAll / WaitAny / WhenAll / WhenAny
开发语言·c#