依赖倒转原则
依赖倒转原则是什么?
依赖倒转原则是设计模式中的一个原则。
那这个原则说的是什么呢?
Robert C. Martin在他的著作《敏捷软件开发:原则、模式与实践》中有这样的两句描述
1.High-level modules should not depend onlow-level modules. Both should depend on abstractions.(高层模块不应该依赖于低层模块,二者都应该依赖于抽象)
2.Abstractions should not depend upondetails. Details should depend upon abstractions.(抽象不应该依赖于具体实现细节,而具体实现细节应该依赖于抽象)
即,模块类之间的依赖是基于抽象类的,实现类之间不能有直接的依赖关系,其依赖关系是通过接口或者抽象类产生的。
其核心思想是:要面向接口编程,不要面向实现编程。
我的理解是,就是做功能尽可能是使用接口或抽象类。
不知道你有没有奇怪,为什么叫依赖倒转?
我画了一个图
在图中上图,上层本来是直接依赖下层的。下图,在引入接口之后,下层要实现接口(受到接口的约束),上层依赖于接口(上层调用接口),这样来看下层间接的依赖于上层。依赖从上层依赖下层,变成了从下层受到上层约束依赖,所以叫依赖倒转。
为什么要使用依赖倒转原则?
1.降低耦合;
你看上图,上层和下层是直接依赖的,在使用了依赖倒转原则之后,上层和下层都和接口建立了关系,上层和下层直接的依赖关系被删除了。这样一来上层和下层的耦合降低了。
2.有利于并行开发;
为什么说有利于并行开发呢?
因为上层直接依赖下层,负责下层代码编写同事修改了代码,上层的代码编写的同事因为依赖关系,也需要进行修改,这需要通知上层的同事进行修改。使用了依赖倒转原则,那么接口,约束了上层的代码开发,也限制了下层的代码开发。写上层代码的同事和写下层代码的同事,不需要相互沟通,只需要各干各的。
3.能够更好的应对变化。
在使用上层直接依赖下层的情况下,需求发生变化,需要修改下层代码,这时上层的代码也需要修改,修改的代码会涉及上层和下层的代码,如果使用依赖倒转原则,当发生需求变化,修改下层代码,可能就不需要修改或修改少量的上层代码。修改的代码越少,也就意味着应对变化所要做的事越少,那么应对变化的速度当然会越快。
为什么说下层的代码修改上层代码也需要修改呢?
我举一个例子你就知道了
你看第一部分代码,这是上层(ZhangSan类)直接依赖下层(Benz类),在他需要扩展增加开宝马的功能,看第二部分代码,他不仅增加了一个下层(BMW类),还在上层(ZhangSan类)中添加了一个重载的drive方法。
作为对比,第三部分是使用依赖倒转原则进行设计,通过设计接口(Icar接口),上层(ZhangSan类)通过依赖Icar接口调用run方法来实现功能,下层(Benz)只要实现Icar接口即可,当他需要扩展增加开宝马的功能,看第四部分代码,只需要增加一个BMW类实现Icar接口的run方法即可完成本次修改。
你看看如果再增加一个开什么车的功能,使用依赖倒转原则设计的代码只需要扩展,不需要对其他的代码进行修改(这无形中遵守了开闭原则,对扩展开放,对修改关闭)。
怎么做?
说了这么多好处,怎么在工作中使用依赖倒转原则呢?
就是编写代码的时候,尽可能使用接口或抽象类(面向接口编程)。但要注意,依赖倒转原则是为了完成功能而服务的,因此在一些特殊情况下,不必非得按照依赖倒转原则设计。我只能说使用了依赖倒转原则,更有利于代码扩展。
面向接口编程怎么去做到呢?
就是将那些不变的的东西固化下来,抽象成接口或抽象类。那些可变的东西,通过实现抽象的接口来完成。