依赖倒置原则(Dependence Inversion Principle, DIP), 其含义:
这里的依赖关系我们理解为UML关系中的依赖。简单的说就是A use B,那么A对B产生了依赖。具体请看下面的例子。
从上图中我们可以发现, 类A中的方法a()里面用到了类B, 其实这就是依赖关系, A依赖了B. 需要注意的是: 并不是说A中声明了B就叫依赖, 如果引用了但是没有真实调用方法, 那么叫做零耦合关系. 如下图:
依赖倒转原则就是要针对接口编程,不要针对实现编程。这就是说,应当使用接口或者抽象类进行变量的类型声明,参数的类型声明,方法的返回类型说明,以及数据类型的转换等。
public class Benz {
public void run() {
System.out.println("奔驰跑起来了!");
}
}
public class Driver {
private String name;
public Driver(String name) {
this.name = name;
}
public void driver(Benz benz) {
benz.run();
}
}
public class CarTest {
public static void main(String[] args) {
Benz benz = new Benz();
Driver driver = new Driver("张三");
driver.driver(benz);
}
}
有一个驾驶员张三可以驾驶奔驰汽车, 于是最开始我们思考, 会有一个驾驶员类, 有一个奔驰汽车类. 随着业务的发展, 我们发现, 驾驶员张三还可以驾驶宝马.
于是,我们定义一个BM类,
public class BM {
public void run() {
System.out.println("宝马跑起来了!");
}
}
这时, 张三如果想要开宝马, 就要将宝马注册在他名下.
public class Driver {
private String name;
public Driver(String name) {
this.name = name;
}
public void driver(Benz benz) {
benz.run();
}
public void driver(BM bm) {
bm.run();
}
}
public class CarTest {
public static void main(String[] args) {
Benz benz = new Benz();
BM bm = new BM();
Driver driver = new Driver("张三");
driver.driver(benz);
driver.driver(bm);
}
}
似乎这样就可以了, 但是这样有什么问题呢?
这就是面向实现编程的问题, 接下来我们就要考虑面向接口编程.
public interface ICar {
public void run();
}
public class Benz implements ICar{
public void run() {
System.out.println("奔驰跑起来了!");
}
}
public class BM implements ICar{
public void run() {
System.out.println("宝马跑起来了!");
}
}
public interface IDriver {
public void driver(ICar car);
}
public class Driver implements IDriver{
@Override
public void driver(ICar car) {
car.run();
}
}
public class CarTest {
public static void main(String[] args) {
IDriver driver = new Driver();
driver.driver(new Benz());
driver.driver(new BM());
}
}
修改后的代码, 提炼出来一个IDriver接口和ICar接口, 面向接口编程. IDriver的实现类驾驶员可以driver任何类型的汽车, 所以传入参数也是一个接口ICar. 任何类型的汽车, 都可以通过实现ICar接口注册为一种新的汽车类型. 当客户端调用的时候, 将对应的汽车传入就可以了.
1 构造注入,在构造的时候注入依赖