Dependence Inversion Principle, DIP
定义
1.高层模块不应该依赖底层模块,两者都应该依赖其抽象
2.抽象不应该依赖细节
3.细节应该依赖抽象
即:
1.模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
2.接口或抽象类不依赖于实现类
3.实现类依赖接口或抽象类
优点
1.减少类间的耦合性,提高系统稳定性
举个栗子:
/*
* 司机
*/
public class Driver {
//司机的主要职责就是驾驶汽车
public void drive(Benz benz) {
benz.run();
}
}
/*
* 奔驰汽车
*/
public class Benz {
//汽车肯定会跑
public void run() {
System.out.println("奔驰汽车开始运行...");
}
}
/*
* 司机开车场景模拟
*/
public class Client {
public static void main(String[] args) {
Driver zhangSan = new Driver();
Benz benz = new Benz();
//张三开奔驰车
zhangSan.drive(benz);
}
}
现在司机不仅要开奔驰车,还要开宝马车:
/*
* 宝马车
*/
public class BMW {
//宝马车开动
public void run() {
System.out.println("宝马汽车开始运行...");
}
}
但是我们现在发现,司机并不能开宝马车。这显然不合理,原因就是司机类和奔驰类是紧耦合的关系,这样一旦有新的车,比如宝马车来了,司机类就需要改动它的类代码,维护性大大降低,不稳定。
2.降低并行开发引起的风险,提高代码的可读性和可维护性。
现在开发的时候人员都是协作开发,可能每个人负责一个模块,也可能每个人负责一个类的编写或方法的编写。假如现在司机类由A来编写,奔驰车类由B来编写,很显然,在B编写完之前,A是不能开发成功的,为什么呢?编译器就不通过了,只能B开发完奔驰车类再由A来开发司机类,这样显然不利于项目进度,所以要解决模块之间的依赖关系。
按照依赖倒置原则,我们所有的高层模块都应该依赖于接口或抽象类。
/*
* 司机接口
*/
public interface IDriver {
//司机会驾驶汽车
public void drive(ICar car);
}
/*
* 司机
*/
public class Driver implements IDriver{
//司机的主要职责就是驾驶汽车
// public void drive(Benz benz) {
// benz.run();
// }
@Override
public void drive(ICar car) {
car.run();
}
}
/*
* 汽车接口
*/
public interface ICar {
//汽车都能跑
public void run();
}
/*
* 奔驰汽车
*/
public class Benz implements ICar{
//汽车肯定会跑
public void run() {
System.out.println("奔驰汽车开始运行...");
}
}
/*
* 宝马车
*/
public class BMW implements ICar {
//宝马车开动
public void run() {
System.out.println("宝马汽车开始运行...");
}
}
/*
* 司机开车场景模拟
*/
public class Client {
public static void main(String[] args) {
Driver zhangSan = new Driver();
Benz benz = new Benz();
//张三开奔驰车
zhangSan.drive(benz);
//张三开宝马车
zhangSan.drive(new BMW());
}
}
这时我们要让司机开宝马车只需要实现汽车接口即可,司机类不需要改动任何代码,即接口或抽象类(IDriver)并不依赖于汽车时哪一种的(细节)。
依赖的三种写法
这里的原理是依赖是可以传递的,只要做到抽象依赖,那么多层的传递也是正确的。
构造函数注入
/*
* 司机接口
*/
public interface IDriver {
//司机会驾驶汽车
public void drive(ICar car);
}
public class Driver implements IDriver{
private ICar car;
//构造函数注入
public Driver(ICar _car) {
this.car = _car;
}
//司机的主要职责就是驾驶汽车
public void drive() {
this.car.run();
}
}
setter依赖注入
/*
* 司机接口
*/
public interface IDriver {
//车辆型号
public void setCar(ICar car);
//司机会驾驶汽车
public void drive(ICar car);
}
public class Driver implements IDriver{
private ICar car;
//构造函数注入
public void setCar(ICar _car) {
this.car = _car;
}
//司机的主要职责就是驾驶汽车
public void drive() {
this.car.run();
}
}
接口声明依赖对象
/*
* 司机接口
*/
public interface IDriver {
//车辆型号
public void setCar(ICar car);
//司机会驾驶汽车
public void drive(ICar car);
}