一、DIP定义
定义:DIP(DIP-Dependency Inversion Principle),即依赖倒置原则
1、高层模块不应该依赖于低层模块,二者都应该依赖于抽象。[1]
2、抽象不应该依赖于细节,细节应该依赖于抽象,要针对接口编程,不要针对实现编程。
依赖:在程序设计中,如果一个模块a使用/调用了另一个模块b,我们称模块a依赖模块b。
高层模块与低层模块:往往在一个应用程序中,我们有一些低层次的类,这些类实现了一些基本的或初级的操作,我们称之为低层模块;另外有一些高层次的类,这些类封装了某些复杂的逻辑,并且依赖于低层次的类,这些类我们称之为高层模块。[5]
高层模块包含了一个应该程序中的重要的策略选择和业务模型,正是这些高层模块才使得其所有的应用程序区别于其他,如果高层依赖于低层,那么对低层模块的改动就会直接影响到高层模块,从而迫使它们依次做出改动。
具体原则是:
1) 任何变量都不能拥有一个具体类的指针或者引用。
2)任何类都不应该从具体类派生。
3)任何方法都不应该覆写基类中已经实现的方法。
也就是说应当使用接口和抽象类进行变量类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等,而不要用具体类进行变量的类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。要保证做到这一点,一个具体类应当只实现接口和抽象类中声明过的方法,而不要给出多余的方法。
基于这个原则,设计类结构的方式应该是从上层模块到底层模块遵循这样的结构:上层类--->抽象层--->底层类。[4](High Level Classes(高层模块) --> Abstraction Layer(抽象接口层) --> Low Level Classes(低层模块)[5])。
Robert C. Martin氏给出的DIP方案的类的结构图:
PolicyLayer-->MechanismInterface(abstract)--MechanismLayer-->UtilityInterface(abstract)--UtilityLayer[5]
类与类之间都通过Abstract Layer来组合关系。
二、举例说明
以前面我们做的画圆和画方形中类为例:
TShape *AShape=new TCircle(CPoint(rand()%480,rand()%300),10+rand()% 100);
TShape *AShape=new TRectangle(CPoint(a,b),CPoint(a+offset1,b+offset));
程序在创建对象过程中依赖了具体类,如果TCircle或TRectangle变化将会引起TShape的变化。
解决的方法是再抽象出一个中间层,使创建对象的过程与TShape无关。这样抽象就不会依赖于细节,这就是DIP。
三、优点
依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。
总言之,这个原则的本质就是用抽象(接口或者抽象类)来使高层模块独立于底层模块,以达到高层的自由复用! 该原则是做“Framework”设计的核心。
应用该原则意味着上层类不直接使用底层类,他们使用接口作为抽象层。这种情况下上层类中创建底层类的对象的代码不能直接使用new操作符。可以使用一些创建型设计模式,例如工厂方法,抽象工厂和原型模式。
模版设计模式是应用依赖倒转原则的一个例子。
当然,使用该模式需要额外的努力和更复杂的代码,不过可以带来更灵活的设计。不应该随意使用该原则,如果我们有一个类的功能很有可能在将来不会改变,那么我们就不需要使用该原则。[4]
开-闭”原则与依赖倒转原则是目标和手段的关系。如果说开闭原则是目标,依赖倒转原则是到达"开闭"原则的手段。
四、回音
当然了,这个原则的应用场景,也是存在一定的讨论的,网友age0就说“实际编码要要依赖于具体,不要依赖于抽象,判依赖倒置原则,仅限于业务抽象分析领域“[2];HairRoot也表示也自己的看法,认为”这个原则对于那些虽然具体但是却稳定的类来说似乎并不是很合适,如string类“[3],网友蹩脚馒头认为”开发初期很多需求是不明确的变化的,无法做到抽象。在重构的时候潜意识里有这个思想就可, 作为启发性原则! 无法认同作为一个开发原则!“[6]
参考:
1、http://www.cnblogs.com/feipeng/archive/2007/03/02/661812.html
2、http://www.javaeye.com/topic/7042
3、http://hairroot.blogchina.com/blog/4413501.html
4、http://gaojiewyh.javaeye.com/blog/485273
5、http://www.lifevv.com/sysdesign/doc/20071204143736206.html
6、http://sshc625.com/article.asp?id=80