当前位置:网站首页>如何遵循“低耦合”设计原则?
如何遵循“低耦合”设计原则?
2022-07-24 17:41:00 【用户6557940】
类的设计需要遵循“高内聚、低耦合”的设计原则(或者说“高内聚、松耦合”)。什么是高内聚和低耦合:
- 高内聚:内聚是对软件系统中元素职责相关性和集中度的度量。如果元素具有高度相关的职责,除了这些职责内的任务,没有其它过多的工作,那么该元素就具有高内聚性。
- 低耦合:耦合是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据
某种程度上理解,高内聚低耦合也是单一职责原则、迪米特法则的另一种体现。
结合项目上开发的经历,要将一个类设计为高内聚和低耦合的类,难的是实现和后期应对临时需求和corner case而增加的改动。当然,这也是没有良好设计种下的苦果。这种痛苦,会在某次增加feature时感受到,也可能是在重构的时候。总之,虽迟但到。
下面先看一个违背低耦合设计原则的示例。考虑如下一个示例:按钮控制电灯开关。
#include <iostream>
#define ON true
#define OFF false
class Lamp
{
public:
void on() {
// ...
}
void off() {
// ...
}
};
class Button
{
public:
Button(Lamp& lamp): mLamp(lamp){}
void touch() {
if (mState == ON) {
mState = OFF;
mLamp.off();
}
else {
mState = ON;
mLamp.on();
}
}
private:
Lamp& mLamp;
bool mState{OFF};
};这段代码是可以正常运行的,乍一看也没什么问题:
- 创建电灯Lamp的实例。
- 再创建Button的实例,并将Lamp对象的引用传给Button构造函数。
- 接下来只需调用Button对象的touch()函数,即可控制电灯的开关状态。
这有什么问题吗?当然有问题——将Lamp对象的引用传给Button。这样Button内部就知道了lamp。但问题是,我们去买一个按钮开关的时候,按钮开关知道电灯吗?按钮开关还可以控制洗衣机、风扇、中央空调……那我们是不是要把所有这些可用按钮开关控制的对象的引用都传给按钮开关呢?
Button需要知道这么多吗?显然不需要,不需要将Button与其控制的具体对象耦合起来。这显然违背了低耦合的设计原则。Button只需要控制一个可用开关控制的对象即可,至于这个对象具体是什么,Button无需了解。电灯也好,电视、风扇、空调、洗衣机也罢,它们同属于可用开关控制的对象,都具有“打开”和“关闭”两种状态,那么就让它们继承自一个共同的基类即可:
扩展地,如果一个Button可以同时控制多个对象,那么就在Button内部维护一个列表吧。
Jungle回去再翻看了下命令模式:作为程序员的你,必须要知道命令模式!
同样,代码实例中举的是开关控制点灯和电风扇的场景:
我原以为之前的设计会违背“低耦合”原则:Button内部直接控制Lamp和Fan。这就需要将Lamp对象和Fan对象以指针或引用(或者其他形式)传递给Button,然后Button内部操作这些对象。如果真这么设计,就犯了上面第二点中提到的错误。
这里的设计也符合“低耦合”的设计原则,只将一个抽象的Command传递给Button。Button并不知道Command细节,即,Button和Command并没有耦合在一起。如果要增加被控制的对象,那么直接继承自Command就可以了,无序改动已有的代码,这也符合开闭原则。
上面的示例也可以看出,降低耦合的办法之一是,引入抽象类(或者接口)。使对象依赖于抽象,而不是依赖于具体。这其实也是依赖倒转原则的要求。
第二种办法是,使用并严格遵循一些既有的设计模式,比如中介者模式、命令模式、适配器模式等。因为设计模式本身就是为了解决某类重复出现的问题而出现的一套成功或有效的解决方案。Just follow it!
另一种办法是引入分层。某种程度上来说,设计模式的使用,或者抽象类的引入,就是分层的一种体现。通过引入中间层,引入抽象层,来降低类与类之间的耦合。不过,引入分层,往往需要初期对项目有完整的规划。
温故而知新,就说这么多~
边栏推荐
- After separation, the impression notes are still difficult to live, but there are many coquettish operations
- Colleges and universities have introduced 23 Philippine doctors with heavy funds, and the relevant departments have launched an investigation!
- Pay close attention! List of the latest agenda of 2022 open atom open source Summit
- 再见收费的Navicat!这款开源的数据库管理工具界面更炫酷!
- hcip第三天
- Still using xshell? You are out, recommend a more modern terminal connection tool!
- SV强制类型转换和常数
- Portmap port forwarding
- 213. Looting II - Dynamic Planning
- UFW port forwarding
猜你喜欢
随机推荐
Is computer monitoring true? Four experiments to find out
Portmap port forwarding
Common questions of testers during interview
Six ways for JS to implement inheritance
邻接表的定义和存储以及有向图无向图的邻接存储
Definition and storage of adjacency table and adjacency storage of directed graph and undirected graph
Demonstration experiment of scrollbar for adjusting image brightness
SV casts and constants
HCNP Routing&Switching之DHCP中继
Class bytecode file
hcip第四天笔记
实习报告1——人脸三维重建方法
DHCP relay of HCNP Routing & Switching
Natbypass port forwarding
The solution of single chip microcomputer not supporting printf floating point type
700. Search DFS method in binary search tree
还在用Xshell?你out了,推荐一个更现代的终端连接工具!
Openlayers: point aggregation effect
数论整除分块讲解 例题:2021陕西省赛C
Logical operation of image pixels









