设计模式六大原则解读——什么是依赖倒置
author:陈镇坤27
创建日期:2022年1月31日
——————————————————————————————
一、依赖倒置
1、依赖倒置的定义
官方原文定义为
High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.
即:高层模块不依赖底层模块。两者都依赖彼此的抽象。抽象不依赖细节。细节依赖抽象。
在Java中,可以被实例化的为细节,接口和抽象类为抽象。
高层模块由底层模块组装而成。例如client调用中,注入的是细节的抽象,则说该高层模块与底层模块的耦合符合依赖倒置原则。
2、依赖倒置的目的
有助于减少类间耦合;降低并行开发风险。
例子:司机开奔驰
ps:司机与奔驰是依赖关系。
Driver开车,车是底层模块,而Driver是高层模块,Benz是底层模块。
高层模块对底层模块的调用,如果形参是细节,而非abstract,那么当我们想要更换新车时,便只能徒增新方法。
此外,Client对司机和Benz的引入,都是直接与其细节产生关系,这也不利于将来Client可能产生的更新迭代。且提高了并行开发的难度。
例如a开发需要去做司机模块,而b开发需要去做Client模块。由于a开发还没做完司机模块,那么依赖于其细节的Client模块的开发就会遇到阻碍。
正确的做法是在模块与模块的关联间,利用抽象提高可维护性。
修正后应如下:
可能会有人说,在高层模块Client中,为了司机开其他车,在实例化Driver,调用方法时,需要替换新的细节。但这些细节的表面类型是其接口,屏蔽了高层模块对细节的依赖。此外司机类不需要做变动,已然将底层模块的替换对高层模块的变动风险降低到最小程序。
3、建议
模块间的依赖耦合需要抽象。一般地,有三种建立模块依赖的方式
3.1、构造函数传递依赖
将依赖目标作为成员变量,该成员变量的表面类型为抽象,靠构造函数方式注入该成员变量的真实类型。再建立一个成员方法,调用该抽象的方法。
3.2、Setter方法传递依赖
将依赖目标作为成员变量,该成员变量的表面类型为抽象,靠Setter方式注入该成员变量的真实类型。再建立一个成员方法,调用该抽象的方法。
3.3、接口传递依赖
直接将该细节的抽象作为形参的表面类型,在成员方法内调用抽象的方法。
4、总结
变量尽量声明表面类型为接口类或抽象类;
模块间的耦合尽量通过接口进行;
如果模块声明的表面类型是抽象类,那抽象类的子类应该尽量不要复写抽象类自身内部已经实现了的方法,否则会影响父类的稳定性。(这是依循依赖倒置原则后,需要注意的问题)
依赖倒置主要针对接口与实现类,里氏替换主要针对父子抽象类。抽象类负责公共部分的实现。
|