《架构整洁之道》第 11 章 DIP:依赖反转原则

2023-05-27 07:59:16 浏览数 (3)

均为原创,读架构整洁之道的笔记。

依赖反转原则:(DIP :Dependency Inversion Principle)。

如果想要设计一个灵活的系统,再源代码层次的依赖关系中,就应当多引用抽象类型,而非具体实现

也就是说在静态类型的编程语言中,如GoJava,在引入包或文件时,应当只引入抽象类或接口,而不应当引用任何具体的实现

但做不到完全引用接口或抽象类,如Java中的String,就是一个具体实现,如类似的非常稳定的类,系统原生提供的类,则不在此依赖反转的范围内。我们应当关注自己的业务中,容易变动的模块

稳定的抽象层

为什么要使用抽象的,而非具体实现呢?

因为每当我们修改接口时,就必然伴随着去修改那些具体的实现。但我们修改具体实现时,却很少修改对应的接口。这就可以认定,接口比实现稳定,如果想要追求架构上的稳定,就必须多使用抽象的,少依赖多变的具体实现。

具体的编码守则:

  1. 多使用抽象接口,尽可能的避免依赖多变的具体实现。对象的创建也要受到严格限制,通常用抽象工厂来创建对象。
  2. 不要在具体实现类上,创建衍生类。继承关系是源代码依赖最强最难被修改的。
  3. 不要覆盖包含具体实现的函数。因为函数内可能会依赖类中的属性,依赖关系太强。
  4. 避免在代码中写入任何具体实现的相关名字,如写死的类名。或是其他容易变动的事物名字。

工厂模式

如果想要遵守上述守则,就必须要对易变的对象的创建过程做处理,因为在所有的编程语言中,创建对象的过程都避免不了依赖那些对象的具体实现。如你要new一个对象,那你必须知道那个名字并引入它,就形成了依赖。

一般我们会选择使用抽象工厂模式来解决这个源代码依赖问题。

以那条红色的线为作为区分,作为边界。红线之上为抽象层(高阶业务层),之下为具体实现层(具体操作相关细节)。

再看控制方向,Application是通过控制接口,来获取ConcreteImpl的。

而具体实现层,是由具体实现来操控具体实现的。控制流(抽象层)跨越架构的边界(红线),与源代码(具体实现)跨越该边界的方向是相反的。

这就是DIP被称为依赖反转的原因。避开了直接依赖具体实现。

具体实现组件

上图中,可以看到具体实现组件中,还是有依赖关系,ServiceFactoryImpl依赖ConcreteImpl。这条依赖关系实际上是违反DIP的。但这种情况很常见,因为我们不可能完全消除违反DIP的情况。但是我们必须做到把它们集中到少部分的具体实现组件中,要和高阶业务隔离开来。

如入口main函数,就必须依赖到一个具体实现,才能开始调用。

本章小结

主要关注那条红色曲线,那是架构边界。

1 人点赞