周末在看《深入理解Java虚拟机》,其中有关于Java虚拟机部分的描述,忽然来了灵感,感觉可以从这个角度来阐述 依赖倒置 设计原则。
最初接触 依赖倒置,是在《HeadFirst设计模式》这本书中,此后,每当业务重构或者开始一个新项目,我都会先翻一翻这本书,常读常新,每次也都会有新的体悟。
一、破题 - Java虚拟机规范和语言规范
Java
在刚刚诞生之时曾经提出过一个非常著名的宣传口号:“一次编写,到处运行”。“与平台无关” 的理想最终实现在操作系统的应用层上:Sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现了程序的 “一次编写,到处运行”。各种不同平台的虚拟机与所有操作系统平台都使用同一程序存储格式–字节码(ByteCode),这也是平台无关性的基石。
有了Java语言,程序员就可以忽略具体操作系统平台(Win、Mac、Linux等)、忽略特定硬件底层指令集(x86、ARM等),只需要关注Java语言规范,就可以“一次编写,到处运行”。
二、编程思维的依赖倒置
2.1、在 Java 语言出来之前:
程序员需要依赖特定操作系统来完成具体的工作。例如:绘制一个圆,需要调用不同操作系统的GUI绘制库来完成,库的名称以及API接口是不同的,都需要在代码中具体适配。
从依赖关系来看,高层 的应用程序,依赖 低层 的操作系统绘制库。
每当新增一个运行平台,就是在新增依赖一个绘制库。另外,后续该绘制库API改变了或者有了调整,高层的应用程序也需要跟着调整。
2.2、在 Java 语言出来之后:
程序员只需依赖 Java语言规范 即可完成具体的工作,不需要关心平台。例如:绘制一个圆,调用 Java GUI 库的API,Java 虚拟机会与特定的操作系统平台对接,绘制一个圆。
再去看依赖关系,高层 的应用程序,依赖 Java虚拟机或者语言规范,低层组件也依赖Java虚拟机或者语言规范完成功能对接。
每当新增一个运行平台,只要该平台支持 Java虚拟机或者语言规范 ,就什么都没有发生改变,后续该平台绘制库API改变了或者有了调整,高层的应用程序亦不需要跟着调整。
在Java语言出现的前后,程序编写的思维方式也跟着发生了改变。从 高层组件 依赖 低层组件,到 高层组件 和 低层组件 都依赖于 抽象,这里的 抽象 就是 Java虚拟机或者语言规范,或者说 Java 虚拟机 。
三、这和我们的依赖倒置设计原则有什么关系呢?
其实,上面的开发思维就是“依赖倒置”设计原则,依赖倒置设计原则有如下几种不同的说法:
- 要依赖抽象,不要依赖具体类
- 针对接口编程,不针对实现编程。
- 不能让高层组件依赖低层组件,两者都应该依赖于抽象。
刚刚接触这个设计模式时,最困惑的莫过于:依赖倒置原则,究竟倒置在哪里?
依赖倒置设计原则中的“倒置”指的是和一般的面向对象的思考方法完全相反。正常思维,先从顶端设计开始,然后往下到具体的低层类设计。依赖倒置设计原则要求我们先别从顶层开始,而是先看看能“抽象化”些什么。
总结
实际的案例中,完美应用依赖倒置设计原则非常难,尤其是新业务的工程架构设计,往往业务稳定铺开一段时间之后,抽象模型才会慢慢变得“清晰”。
更普遍的场景往往是,新需求无法在旧业务架构实现中迭代,不得不做架构设计调整(架构调整的第一目标就是调整前后,业务效果要一模一样,对用户来讲要像什么都没发生过一样。由于不产生新的增量,不到万不得已,不会做架构调整的)。
踩过坑,才会体会依赖倒置的强大,不说了,说多了都是眼泪。