依赖倒置原则(Dependency Inversion Principle: DIP)
高层模块不应该依赖于底层模块,二者应该都依赖于抽象
抽象不应该依赖于具体细节,细节应该依赖于抽象
这里的所有观点摘抄自《敏捷软件开发原则、模式与实践》,原著Robert C. Martin,邓辉等译。
其实依赖倒置的原则很好理解,但是在实际应用中却不容易识别出来。
现实中有很多这样的例子,例如客厅里面要放置一个沙发。一种方案是,先去挑好沙发,然后根据沙发的形状和尺寸来
然后把客厅改造成合适沙发的样子。此时可以看到客厅的形状就会严重依赖于沙发的形状。另外一种办法,则是预先
设计好房子的格局。然后去根据客厅的大小尺寸来挑选合适的沙发。
这个例子里面,房子就是高层模块,不会经常变动,沙发属于底层模块。两者依赖的抽象是什么呢,就是房子里面预留
的沙发的尺寸以及根据布局所决定的沙发的样式颜色。
层次化
书里面引用了Booch的一段话:"所有结构良好的面向对象框架都具有清晰地层次定义,每个层次通过一个定义良好
的、受控的接口向外提供了一组内聚的服务。"
Booch是谁?UML语言的创立者。
也就是说,一个好的面向对象设计,都应该是层次清晰的。一旦有了层次,那就会有高层次和低层次之分,随之而来
的也就有了依赖关系。我们习惯于把稳定的,不怎么发生改变的层称为高层次。把经常发生变化的,可以被替代的称为
低层次。
这样的例子如,电脑内部的主板和显卡,主板和内存,主板和CPU之间的关系。主板处于一个相对稳定的结构,所以属于
高层次,而其他的配件都是经常发生变化的部分,所以属于低层次。
回到DIP的话题,高层次和低层次究竟是一个什么样的关系,究竟谁占主导地位,谁依赖于谁。我们先来看一下高层次
依赖于低层次。拿上面的例子来说,就是内存,显卡,CPU占主导地位,主板使用了内存,显卡,CPU所提供的方法。这样
一来,无论是内存,显卡还是CPU,只要其中一个进行更换,那么主板要相应的进行更换。这对消费者来说,简直就是个
灾难性的事情。
再来考虑,低层次依赖于高层次。这样一来,主板只需要定义好需要的接口,低层的内存,CPU,显卡根据这个接口来提供
具体的实现。
传统概念中,高层次要适配低层次,因为是低层次提供了对外的接口,高层次只能依赖于低层次所提供的接口,没有任何的
自主性。联想到计划经济的产品的生产,就是这样。DIP意味着主动权在(接口)高层次,在使用接口的人手上,高层次
需要什么,低层次就提供什么。同样接口的作用也实现了高低层次之间的解耦。
著名的Hollywood原则:"Don't call us, we'll call you."
抽象
DIP中很关键的概念就是抽象。DIP建议所有的依赖关系都应该终止于抽象类或者接口。
- 任何变量都不应该持有指向具体类的指针或者引用
这点很好理解,具体类的变化会导致依赖关系的不稳定,从而违反了DIP。
- 任何类都不应该从具体类派生
依然是因为具体类的改变,会导致派生类依赖于具体类的改变。违反DIP。
- 任何方法都不应该覆写任何基类中已经实现了的方法
网友评论