前言
上一节我们说了接口隔离原则,就是让接口的职责最小化。这样对维护代码简单,调用方法也清晰。
这节我们来研究依赖倒置原则。这个原则我认为是特别特别重要的。在很多地方我们能看到。比如Dubbo中使用到的SPI等等。
基本介绍
什么是依赖倒置原则?
我们可以将其分为两点:
1) 高层模块不应该依赖低层模块,二者都应该依赖其抽象
2) 抽象不应该依赖细节,细节应该依赖抽象
其实总结下来,依赖倒转(倒置)的中心思想是面向接口编程
相对于细节的多变性,抽象的东西要稳定的多。
我们以抽象的接口为基础来架构我们的项目比以细节为基础的架构要稳定的多。
在java中,抽象指的是接口或抽象类,细节就是具体的实现类
使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
案例
上面干巴巴的文字需要多读几遍,然后再来看案例。
反例
首先,我们来说明一个反例,如果没有使用依赖倒置原则会有什么问题?
public class Audi {
public void run(){
System.out.println("开奥迪上班");
}
}
class Person{
public void goToWork(Audi car){
car.run();
}
public static void main(String args[]){
Person person = new Person();
Audi audi = new Audi();
person.goToWork(audi);
}
}
上诉代码输出结果为:
开奥迪上班
大家思考一下这样的设计有没有问题?
很明显,如果这个人换了一辆车,我们是不是需要改Person类的源代码??
我们在Person这个类中实现了goToWork() 上班这个方法。并且传入了奥迪车这个对象。
如果我们想换一辆车,只能修改goToWork()这个方法,传入你想开的车。
这样设计出来的代码很不灵活。
我们来看看正确的做法是什么。
使用依赖倒置原则
public class Audi {
public void run(){
System.out.println("开奥迪上班");
}
}
public class Jili {
public void run(){
System.out.println("开国产神车吉利上班");
}
}
public interface Car {
void run();
}
class Person{
public void goToWork(Car car){
car.run();
}
public static void main(String args[]){
Person person = new Person();
Audi audi = new Audi();
Jili jili = new Jili();
person.goToWork(audi);
person.goToWork(jili);
}
}
上诉代码输出结果
开奥迪上班
开国产神车吉利上班
不知道大家能不能从中看出实现依赖倒置原则的优势?
没错,这下我们想开什么车就开什么车,不需要再去修改源代码了。
这下我们再来理解之前的话,就清晰很多了。
相对于细节的多变性,抽象的东西要稳定的多。
我们以抽象的接口为基础来架构我们的项目比以细节为基础的架构要稳定的多。
总结
依赖倒置原则就是我们的抽象父类指向子类或者是抽象接口指向实现类的思想。
平常开发多留意,你一定会发现很多地方用到了这个原则思想。
但是这个设计也有一个缺点就是,我们在具体的实现类中实现了接口中没有的方法,那么此时这个方法是调用不了的,为什么?后面的jvm系列我们会单独来分析这一块。
所以,比较理想的状态就是使用接口或抽象类制定好规范,具体的实现类严格参考该接口或者抽象类。