C++ 代码整洁之道:C++17 可持续软件开发模式实践 (32):原则 3.7

阅读数:5 2019 年 12 月 8 日 20:00

C++代码整洁之道:C++17可持续软件开发模式实践(32):原则 3.7

(松耦合原则)

内容简介
本书致力于讲述 C++ 整洁代码之道!如果你想让自己写的代码更加整洁,那么这本书适合你阅读。本书需要熟悉 C++ 语言的基本概念,才能有效的掌握其中的内容。如果你只是想从 C++ 开发开始,并且没有 C++ 语言的基础知识,你应该首先选择一个好的 C++ 入门的练习项目。此外,本书也不包含任何深奥的技巧和杂乱的知识点。我知道 C++ 有很多令人兴奋的技巧,但这些通常不是整洁代码的精神,也不是现代 C++ 的代码风格。除此之外,这本书为了帮助 C++ 程序员提高技能水平,并举例说明如何编写易于理解的、灵活的、可维护的和高效的 C++ 代码。即使你是一个经验丰富的 C++ 开发人员,这本书中也有一些值得学习的地方,我认为这些值得学习的地方能够促进你的工作。书中所提出的原则和实践可以应用于新的软件系统,有时被称为“绿地项目”,以及具有悠久历史的遗留系统,通常被称为“棕地项目”。

考虑下面的示例代码:

代码 3-5 一种可以开灯和关灯的开关

复制代码
class Lamp {
public:
void on() {
//...
}
void off() {
//...
}
};
class Switch {
private:
Lamp& lamp;
bool state {false};
public:
Switch(Lamp& lamp) : lamp(lamp) { }
void toggle() {
if (state) {
state = false;
lamp.off();
} else {
state = true;
lamp.on();
}
}
};

这段代码基本上可以正常运行。首先你需要创建 Lamp 类的实例,然后通过引用方式将 Lamp 的实例传递给 Switch。这个小例子看起来像图 3-4 描述的那样。

C++代码整洁之道:C++17可持续软件开发模式实践(32):原则 3.7

图 3-4 Switch 和 Lamp 的类图

这个设计有什么问题?

问题就是,我们的 Switch 类直接包含了一个具体类 Lamp 的引用。换句话说,这个 Switch 类知道那是一个具体的 Lamp 类。

也许你会争辩说:“好吧,这就是开关的目的,开关必须能够开灯和关灯。”我会说:“是的,如果这是开关应该做的唯一的一件事情,那么这个设计就足够了。但是,请你去商店看看,卖开关的人知道灯的存在吗?”

你对这个设计的可测试性有什么看法?在单元测试中,SWitch 类可以被单独测试吗?显然这是不可能的。当开关不仅需要打开灯、打开风扇、打开电动卷帘时,我们该怎么办?

在上面的例子中,灯和开关是紧耦合的。

在软件开发过程中,应该寻求模块间的松耦合(也称为低耦合或弱耦合)。这意味着你应该构建一个系统,在该系统中,每个模块都应该很少使用或不知道其他独立模块的定义。

软件开发中,松耦合的关键是接口。接口声明类的公共行为,而不涉及该类的具体实现。接口就像合同,而实现接口的类负责履行契约,也就是说,这些实现接口的类必须为接口的方法签名提供具体的实现。

在 C++ 中,使用抽象类实现接口,如下所示:

代码 3-6 Switchable 接口

复制代码
class Switchable {
public:
virtual void on() = 0;
virtual void off() = 0;
};

这个 Switch 类不再包含 Lamp 类的引用。相反,它持有了我们新定义的 Switchable 接口类。

代码 3-7 改进后的 Switch 类,灯不见了

复制代码
class Switch {
private:
Switchable& switchable;
bool state {false};
public:
Switch(Switchable& switchable) : switchable(switchable) {}
void toggle() {
if (state) {
state = false;
switchable.off();
} else {
state = true;
switchable.on();
}
}
};

这个 Lamp 类实现了我们新定义的 Switchable 接口。

代码 3-8 Lamp 类实现了 Switchable 接口

复制代码
class Lamp : public Switchable {
public:
void on() override {
// ...
}
void off() override {
// ...
}
};

用 UML 类图表示,我们新设计的类图看起来像下图 3-5 那样。

C++代码整洁之道:C++17可持续软件开发模式实践(32):原则 3.7

图 3-5 通过 Switchable 接口,实现了 Switch 和 Lamp 的松耦合

这个设计的优点是显而易见的。Switch 已经能完全独立于由它控制的具体类。而且,Switch 可以通过实现 Switchable 接口的测试替身进行独立的测试。如果你想控制一个风扇而不是一盏灯呢?也没有问题,这个设计对扩展是开放的。只需要创建一个实现了 Switchable 接口的风扇类或者电气设备的其他类就可以了,详见图 3-6。

C++代码整洁之道:C++17可持续软件开发模式实践(32):原则 3.7

图 3-6 通过 Switchable 接口,Switch 能够控制不同种类的电气设备

松耦合可以为系统的各个独立的模块提供高度的自治性,该原理可以适用于很多不同的层次:可以用在最小的模块上,当然,还可以用在大型组件的体系结构上。高内聚会促进松耦合,因为具有明确定义责任的模块,通常会依赖于较少的其他模块。

C++代码整洁之道:C++17可持续软件开发模式实践(32):原则 3.7

购书地址 https://item.jd.com/12599914.html?dist=jd

评论

发布