依赖倒转原则(DIP)
依赖倒转原则(Dependence Inversion)讲的是:要依赖于抽象,而不依赖于具体。
1 为何倒转:
抽象倒转的目的就是:因为抽象层次应该含有宏观的和重要的商务逻辑,所以应该由抽象层次决定具体层次的实现和具体算法的改变。因为抽象层次含有战略的决策,所以应该有他来决定具体层次的战术的决策。因为抽象层次含有必然性的选择,所以应该由他来指导具体层次的偶然性选择。
2:依赖倒转原则
三种耦合类型:
1) 零耦合(Nil Coupling)关系:如果两个类没有耦合关系,就称之为零耦合
2) 具体耦合(Concrete Coupling)关系:具体耦合发生在两个具体的(可实例化的)类之间,经由一个类对另一个具体类的直接引用造成。
3) 抽象耦合(Abstract Coupling)关系:抽象耦合关系发生在一个具体类金和一个抽象类(或者JAVA接口)之间,是两个必须发生关系的类之间存有最大的灵活性。
什么是依赖倒转原则:
抽象不应当依赖与细节,细节应当依赖于抽象。(Abstractions should not depend upon details. Details should depend upon abstraction)
依赖倒转的另一种表达:
要针对接口编程,不要针对实现编程。(Program to an interface, not an implementation.)
针对接口编程的意思是说:应当使用Java接口和抽象Java类经行变量的类型声明、参量的类型声明、方法的返还类型声明,以及数据类型的转换等。要保证做到这一点,一个具体Java类应该只实现Java接口和Java抽象类中声明过的方法,而不应当给出多余的方法。
变量的静态类型和真实类型
变量被声明是的类型叫做变量的静态类型(Static Type),变量所引用的对象的真实类型叫做变量的实际类型(Actual Type)
代码1
List employees = new Vector();
显然,在上面的代码中,employees变量的静态类型是List,而他的实际类型是Vector
引用对象的抽象类型
在很多情况下,一个Java程序需要引用一个对象。这个时候,如果这个对象有一个抽象类型的话,应当使用这个抽象类型作为变量的静态类型。真就是针对接口编程的含义。
如果“蛋”代表抽象,“鸡”代表具体。假设“蛋”就是Java接口或者Java抽象类,“鸡”是一个具体类,X是一个变量,那么变量的声明类型应当是下面这个样子:
蛋 x = new 鸡();
而不应该是:
鸡 x = new 鸡();
还有一个常见的例子:当创建employee类的例子,就要尽量不要使用如下程序:
Vector employee = new Vector();
而应当使用下面的声明语句:
List employees = new Vector();
这两者的区别就是前者使用一个具体类作为变量的类型,而后者使用一个抽象类型(List是一个Java接口)作为类型。后者的好处,就是在决定将Vector类型转换成ArrayList时,需要改动得很少:
List employees = new ArrayList();
这样一来,程序具有更好的灵活性,因为除去调用构造函数的一行语句外,程序的其余部分根本感觉不到变化。
对象的创建
一般而言,在创建一个对象时,Java要求使用new关键字以及这个类本身。而一旦这个对象已经被创建出来,那么就可以灵活的使用这个对象的抽象类型来引用他。因此,Java语言创建一个对象的过程是违背“开-闭”原则以及依赖倒转原则的。
开闭原则:一个软件实体应当对扩展开发,对修改关闭。也就是“对可变性的封装原则(Principle of Encapsulation of Variation)”
正是因为这个原因,设计模式给出了多个创建模式,特别是几个工厂模式。