Loading... > 解耦的目的是实现代码高内聚、松耦合 # 一、“解耦”为何如此重要? > 如果说重构是保证代码质量不至于腐化到无可救药地步的有效手段,那么利用解耦的方法对代码重构,就是保证代码不至于复杂到无法控制的有效手段。 “高内聚、松耦合”是一个比较通用的设计思想,不仅可以指导细粒度的类和类之间关系的设计,还能指导粗粒度的系统、架构、模块的设计。 代码“高内聚、松耦合”,也就意味着: 代码结构清晰、分层和模块化合理、依赖关系简单、模块或类之间的耦合小,那代码整体的质量就不会差。即便某个具体的类或者模块设计得不怎么合理,代码质量不怎么高,影响的范围是非常有限的。 # 二、代码是否需要“解耦”? 那就是把**模块与模块之间、类与类之间的依赖关系画出来**,根据依赖关系图的复杂性来判断是否需要解耦重构。如果依赖关系复杂、混乱,那从代码结构上来讲,可读性和可维护性肯定不是太好。 # 三、如何给代码“解耦”? ## 1. 封装与抽象 > 封装和抽象可以有效地隐藏实现的复杂性,隔离实现的易变性,给依赖的模块提供稳定且易用的抽象接口。 比如,Unix 系统提供的 open() 文件操作函数,我们用起来非常简单,但是底层实现却非常复杂,涉及权限控制、并发控制、物理存储等等。我们通过将其封装成一个抽象的 open() 函数,能够有效控制代码复杂性的蔓延,将复杂性封装在局部代码中。所以我们在改动 open() 函数的底层实现的时候,并不需要改动依赖它的上层代码,也符合我们前面提到的“高内聚、松耦合”代码的评判标准。 ## 2. 中间层 下面这张图是引入中间层前后的依赖关系对比图。在引入数据存储中间层之前,A、B、C 三个模块都要依赖内存一级缓存、Redis 二级缓存、DB 持久化存储三个模块。在引入中间层之后,三个模块只需要依赖数据存储一个模块即可。  引入中间层可以起到过渡的作用,能够让开发和重构同步进行,不互相干扰。 第一阶段:引入一个中间层,包裹老的接口,提供新的接口定义。 第二阶段:新开发的代码依赖中间层提供的新接口。 第三阶段:将依赖老接口的代码改为调用新接口。 第四阶段:确保所有的代码都调用新接口之后,删除掉老的接口。 ## 3. 模块化 最主要的原因就是将系统划分成各个独立的模块,让不同的人负责不同的模块,这样即便在不了解全部细节的情况下,管理者也能协调各个模块,让整个系统有效运转。 将每个模块都当作一个独立的 lib 一样来开发,只提供封装了内部实现细节的接口给其他模块使用。 像 SOA、微服务、lib 库、系统内模块划分,甚至是类、函数的设计,都体现了模块化思想。如果追本溯源,模块化思想更加本质的东西就是分而治之。 ## 4. 其他设计思想和原则 > “高内聚、松耦合”是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。 ### 4.1、单一职责原则 高内聚会让代码更加松耦合,而实现高内聚的重要指导原则就是单一职责原则。模块或者类的职责设计得单一,而不是大而全,那依赖它的类和它依赖的类就会比较少,代码耦合也就相应的降低了。 ### 4.2、接口隔离原则 — 基于接口而非实现编程 基于接口而非实现编程能通过接口这样一个中间层,隔离变化和具体的实现。 这就相当于将一种强依赖关系(强耦合)解耦为了弱依赖关系(弱耦合)。 ### 4.3、依赖注入 跟基于接口而非实现编程思想类似,依赖注入也是将代码之间的强耦合变为弱耦合。尽管依赖注入无法将本应该有依赖关系的两个类,解耦为没有依赖关系,但可以让耦合关系没那么紧密,容易做到插拔替换。 ### 4.4、多用组合少用继承 继承是一种强依赖关系,父类与子类高度耦合,且这种耦合关系非常脆弱,牵一发而动全身,父类的每一次改动都会影响所有的子类。相反,组合关系是一种弱依赖关系,这种关系更加灵活,所以,对于继承结构比较复杂的代码,利用组合来替换继承,也是一种解耦的有效手段。 ### 4.5、迪米特法则 不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。从定义上,我们明显可以看出,这条原则的目的就是为了实现代码的松耦合。 最后修改:2025 年 07 月 01 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏