理论四:如何通过封装、抽象、模块化、中间层等解耦代码?
大型重构的好手段: 解耦。实现高内聚,低耦合。
- 解耦为何如此重要
- 如何判定代码是否需要解耦
- 如何给代码解耦
解耦为何重要
- 控制代码复杂度。
- 高内聚、松耦合可以让我们聚焦在一个类或者模块中,不需要太多了解其他模块或者类的代码。代码阅读性相对好;而且耦合低了代表着依赖少了,在修改的时候需要涉及到的模块就少了,代码的可维护性也相对好;同时可测试性也好,因为解耦之后我们对于其他模块只需要mock即可。
代码是否需要“解耦”
- 一个方法:在阅读的时候将模块之间、类之间的依赖关系画出来,根据复杂度来判断。
如何给代码解耦
1. 封装与抽象
- 封装和抽象可以隐藏系统的复杂性,隔离实现的易变性,提供稳定且易用的接口。
- 比如Unix系统提供的open()文件操作函数,底层逻辑设计权限控制、并发控制、物理存储等,但是表面使用起来很简单。通过封装可以有效控制复杂代码的蔓延。而且open函数基于抽象而非实现来定义,我们改动的时候也不需要改动依赖他的上层代码。
2. 中间层
- 引入中间层能够简化模块或者类之间的依赖关系。例子如下:
- 在重构时,引入中间层可以起到过渡作用,让开发和重构同时进行。比如某个接口有问题需要修改定义,同时调用它的代码都要改动,如果新开发的代码也用到这里,那就冲突了。我们可以按照如下步骤执行:
- 第一阶段:引入一个中间层,包裹老的接口,提供新的接口定义。
- 第二阶段:新开发的代码依赖中间层提供的新接口。
- 第三阶段:将依赖老接口的代码改为调用新接口。
- 第四阶段:确保所有代码都调用新接口后,删掉老接口。
3. 模块化
- 模块化,不同的模块之间通过API通信,模块之间耦合很小。
- 宽泛来讲,模块化思想到处都有:微服务、lib库,系统内部模块划分等。
4. 其他的设计思想和原则
- 单一职责原则:模块或者类小而单一而非大而全。
- 基于接口而非实现编程:通过接口这个中间层,隔离变化和具体实现。
-
依赖注入:虽然不能将两个类解耦为无依赖关系,但是可以做到热插拔替换。
-
多用组合少用继承:继承深度与复杂度让耦合加深。
- 迪米特法则:不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。从定义上,我们明显可以看出,这条原则的目的就是为了实现代码的松耦合。