架构整洁之道-依赖反转

66 阅读2分钟

源代码依赖与控制流的区别

image.png

如图所示,每个函数的调用都必须要引用被调用方所在的模块。

显然,这样做就导致了我们在软件架构上别无选择。在这里,系统行为决定了控制流,而控制流则决定了源代码依赖关系。

但一旦我们使用了多态,情况就不一样了。

image.png

依赖反转

模块ML1和接口I在源代码上的依赖关系的方向和控制流正好是相反的,我们称之为依赖反转。这种反转对软件架构设计的影响是非常大的。

事实上,通过利用面向编程语言所提供的的这种安全遍历的多态实现,无论我们面对怎样的源代码级别的依赖,都可以将其反转。

在下面的例子中,我们可以用它来让数据库模块和用户界面模块都依赖于业务逻辑模块。

image.png

这意味着我们让用户界面和数据库都成为业务逻辑的插件。也就是说,业务逻辑模块的源代码不需要引入用户界面和数据库这两个模块。

这样一来,业务逻辑、用户界面以及数据库就可以被编译成三个独立的组件或者部署单元(例如jar文件、DLL文件、Gem文件等)了,这些组件或者部署单元的依赖关系与源代码的依赖关系是一致的,业务逻辑组件也不会依赖于用户界面和数据库这两个组件。于是,业务逻辑组件就可以独立于用户界面和数据库来进行部署了,我们对用户界面或者数据库的修改将不会对业务逻辑产生任何影响,这些组件都可以被分别、独立地部署。

对于一个架构师来说,面向对象变成就是以多态为手段对源代码中的依赖关系进行控制的能力,这种能力让软件架构师可以构建出某种插件式架构,让高层策略性组件与底层实现性组件相分离,底层组件可以被编译成插件,实现独立于高层组件的开发和部署。

一个架构设计良好的应用程序应该将状态修改的部分和不需要修改状态的部分分隔成单独的组件,然后用合适的机制来保护可变量。