【温故】设计原则:依赖倒置原则

前言

最近在读《敏捷软件开发 原则、模式与实践》,里面提到了几大设计原则,于是想复习下,并且用C#把文中代码重新写一遍

依赖倒置原则(DIP)

概念

高层模块不应该依赖于低层模块。二者都应该依赖于抽象。

一个简单的例子

违反DIP的例子
// Button类(高层策略)直接依赖具体类
public class Button {
    private Lamp itsLamp;  // 糟糕:高层依赖低层
    public void Poll() {
        if (/* 被按下 */) itsLamp.TurnOn();
        else itsLamp.TurnOff();
    }
}

// Lamp类(低层细节)
public class Lamp {
    public void TurnOn() { /* 开灯 */ }
    public void TurnOff() { /* 关灯 */ }
}
符合DIP的改进设计
// 抽象接口由客户(Button)拥有,定义在高层模块
public interface ISwitchableDevice {
    void TurnOn();
    void TurnOff();
}

// Lamp实现抽象接口(细节依赖抽象)
public class Lamp : ISwitchableDevice {
    public void TurnOn() { /* 开灯 */ }
    public void TurnOff() { /* 关灯 */ }
}

// Button只依赖抽象
public class Button {
    private ISwitchableDevice device;  // 依赖抽象
    public Button(ISwitchableDevice device) => this.device = device;
    public void Poll() {
        if (/* 被按下 */) device.TurnOn();
        else device.TurnOff();
    }
}

// 现在可以轻松扩展
public class Motor : ISwitchableDevice { /* 实现 */ }

动态多态 vs 静态多态

考虑一个控制熔炉调节器的软件。该软件可以从一个IO通道中读取当前的温度,并通过向另一个IO通道发送命令来指示熔炉的开或者关。

违反DIP的原始设计
public class FurnaceController {
    private const int THERM_PORT = 0x86;
    private const int FURN_PORT = 0x87;
    
    public void Regulate(double min, double max) {
        while (true) {
            while (ReadHardware(THERM_PORT) > min) Wait(1);
            WriteHardware(FURN_PORT, 1);  // 打开
            while (ReadHardware(THERM_PORT) < max) Wait(1);
            WriteHardware(FURN_PORT, 0);  // 关闭
        }
    }
}
改进方案A:动态多态性(接口)

运行时动态替换实现,支持模拟器测试。

// 抽象接口
public interface IThermometer { double Read(); }
public interface IHeater { void Engage(); void Disengage(); }

// 高层策略依赖抽象
public class Regulator {
    public void Regulate(IThermometer t, IHeater h, double min, double max) {
        while (true) {
            while (t.Read() > min) Wait(1);
            h.Engage();
            while (t.Read() < max) Wait(1);
            h.Disengage();
        }
    }
}

// 具体实现(细节依赖抽象)
public class HardwareThermometer : IThermometer {
    public double Read() => /* 读取硬件0x86 */ 0.0;
}
public class FurnaceHeater : IHeater {
    public void Engage() => /* 操作硬件0x87 */ ;
    public void Disengage() => /* ... */ ;
}
改进方案B:静态多态性(泛型)

性能更高,但类型在编译时固定,更换实现需重新编译。

// 通过泛型实现编译时多态,无需虚函数开销
public class Regulator<TTherm, THeater>
    where TTherm : IThermometer, new()
    where THeater : IHeater, new() {
    
    private TTherm thermometer = new();
    private THeater heater = new();
    
    public void Regulate(double min, double max) {
        while (true) {
            while (thermometer.Read() > min) Wait(1);
            heater.Engage();
            while (thermometer.Read() < max) Wait(1);
            heater.Disengage();
        }
    }
}

// 使用
var regulator = new Regulator<HardwareThermometer, FurnaceHeater>();
regulator.Regulate(20, 25);

参考文献

敏捷软件开发 原则、模式与实践

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值