依赖倒置原则

依赖倒置原则

定义

高层模块不应该依赖底层模块,二者都应该依赖其抽象

抽象不应该依赖细节,细节应该依赖抽象

针对接口编程,不要针对实现编程

优点

可以减少类之间的耦合性、提高系统稳定性、提高代码可读性和可维护性,可降低修改程序所造成的风险

 

实例

有一个小朋友Geely他是个程序员他喜欢写代码,他目前学习了Java、Python、前端三门语言

public class Geely {
/**
* 面向实现编程
*/
public void studyJavaCourse(){
System.out.println("Geely在学习java课程");
}
/**
* 面向实现编程
*/
public void studyFECourse(){
System.out.println("Geely在学习FE课程");
}
/**
* 面向实现编程
*/
public void studyPythonCourse(){
System.out.println("Geely在学习Python课程");
}
}

测试类(高层,也叫应用层)
public class Test {
public static void main(String[] args) {
Geely geely = new Geely();
geely.studyJavaCourse();
geely.studyFECourse();
geely.studyPythonCourse();
}
}

那么问题来了,假设Geely还要学习Linux课程,那么还得在Geely类中添加学习Linux课程的方法,这就是面向实现编程。Geely就是一个实现类,我们在面向实现编程会发现一个重要的问题,这个实现类是要经常修改的,扩展性比较差。
也就是说我们应用层(Test)的函数(mian)这里面的修改是依赖于底层Geely的实现的。因为我们没有抽象,所以造成应用层(Test)是依赖于Geely这个类的。Test属于应用层是高层模块,Geely是属于低层模块,根据依赖倒置原则高
层次的模块是不应该依赖于低层次的模块的。也就是说Test里面的实现依赖于Geely里面具体的实现,我们要先在Geely里面进行扩展补充,然后在高层里面进行使用。

引入抽象解决面向实现编程的问题

创建一个课程学习的接口

public interface ICourse {
void studyCourse();
}



创建JavaCourse实现Icourse
public class JavaCourse implements ICourse {
public void studyCourse() {
System.out.println("Geely在学习java课程");
}
}


创建FECourse实现Icourse
public class FECourse implements ICourse {
public void studyCourse() {
System.out.println("Geely在学习FE课程");
}
}


改造Geely这个类,也就是说Geely在学习课程的时候,具体的实现类交给高层次模块,而不是针对Geely这个类来编写
public class Geely {
public void studyImoocCourse(ICourse iCourse){
iCourse.studyCourse();
}
}
改造Tets

public class Test {
// v1
//public static void main(String[] args) {
// Geely geely = new Geely();
// geely.studyJavaCourse();
// geely.studyFECourse();
// geely.studyPythonCourse();
// }
public static void main(String[] args) {
Geely geely = new Geely();
geely.studyImoocCourse(new JavaCourse());
geely.studyImoocCourse(new FECourse());
}
}

输出:

  Geely在学习java课程
  Geely在学习FE课程

UML

 

 

 

 

 

上面我们是通过在方法中注入接口的形式来实现的,也可以通过构造器的方式来注入Geely具体里面的实现

 

 

 

构造器实现依赖倒置

 

 

 

改造Geely,使用构造器方式

 

 

public class Geely {
private ICourse iCourse;
public Geely(ICourse iCourse){
this.iCourse = iCourse;
}
public void studyImoocCourse(){
iCourse.studyCourse();
}
}

改造Test

public class Test {
public static void main(String[] args) {
Geely geely = new Geely(new JavaCourse());
geely.studyImoocCourse();
}
}


Setter实现依赖倒置

改造Geely
public class Geely {
private ICourse iCourse;

public void setiCourse(ICourse iCourse) {
this.iCourse = iCourse;
}
public void studyImoocCourse(){
iCourse.studyCourse();
}
}

改造Test

public class Test {
public static void main(String[] args) {
Geely geely = new Geely();
geely.setiCourse(new JavaCourse());
geely.studyImoocCourse();
geely.setiCourse(new PythonCourse());
geely.studyImoocCourse();
}
}

总结
引入依赖倒置原则Geely想学什么课我们都可以在不动Geely这个模块的前提下任意地修改,Test是应用层这个肯定是要改的,相对于细节的多变性,抽象的东西要稳定得多,以抽象为基础搭建起来的架构要比以细节
为基础搭建起来的架构要稳定得多,抽象的目的就是制定好规范和契约。高层模块Geely不依赖Icourse的具体实现,核心思想就是面向接口编程。


posted @ 2020-03-21 19:22  叫熊猫啊  阅读(288)  评论(0编辑  收藏  举报