《C++代码整洁之道:C++17 可持续软件开发模式实践》 —3.7 松耦合原则
3.7 松耦合原则
考虑下面的示例代码:
代码3-5 一种可以开灯和关灯的开关
这段代码基本上可以正常运行。首先你需要创建Lamp类的实例,然后通过引用方式将Lamp的实例传递给Switch。这个小例子看起来像图3-4描述的那样。
这个设计有什么问题?
问题就是,我们的Switch类直接包含了一个具体类Lamp的引用。换句话说,这个Switch类知道那是一个具体的Lamp类。
也许你会争辩说:“好吧,这就是开关的目的,开关必须能够开灯和关灯。”我会说:“是的,如果这是开关应该做的唯一的一件事情,那么这个设计就足够了。但是,请你去商店看看,卖开关的人知道灯的存在吗?”
你对这个设计的可测试性有什么看法?在单元测试中,SWitch类可以被单独测试吗?显然这是不可能的。当开关不仅需要打开灯、打开风扇、打开电动卷帘时,我们该怎么办?
在上面的例子中,灯和开关是紧耦合的。
在软件开发过程中,应该寻求模块间的松耦合(也称为低耦合或弱耦合)。这意味着你应该构建一个系统,在该系统中,每个模块都应该很少使用或不知道其他独立模块的定义。
软件开发中,松耦合的关键是接口。接口声明类的公共行为,而不涉及该类的具体实现。接口就像合同,而实现接口的类负责履行契约,也就是说,这些实现接口的类必须为接口的方法签名提供具体的实现。
在C++中,使用抽象类实现接口,如下所示:
代码3-6 Switchable接口
这个Switch类不再包含Lamp类的引用。相反,它持有了我们新定义的Switchable接口类。
代码3-7 改进后的Switch类,灯不见了
这个Lamp类实现了我们新定义的Switchable接口。
代码3-8 Lamp类实现了Switchable接口
用UML类图表示,我们新设计的类图看起来像下图3-5那样。
图3-5 通过Switchable接口,实现了Switch和Lamp的松耦合
这个设计的优点是显而易见的。Switch已经能完全独立于由它控制的具体类。而且,Switch可以通过实现Switchable接口的测试替身进行独立的测试。如果你想控制一个风扇而不是一盏灯呢?也没有问题,这个设计对扩展是开放的。只需要创建一个实现了Switchable接口的风扇类或者电气设备的其他类就可以了,详见图3-6。
图3-6 通过Switchable接口,Switch能够控制不同种类的电气设备
松耦合可以为系统的各个独立的模块提供高度的自治性,该原理可以适用于很多不同的层次:可以用在最小的模块上,当然,还可以用在大型组件的体系结构上。高内聚会促进松耦合,因为具有明确定义责任的模块,通常会依赖于较少的其他模块。
- 点赞
- 收藏
- 关注作者
评论(0)