# 依赖倒置原则

定义:高层模块(指应用模块)不应该依赖底层模块,二者都应该依赖其抽象

  • 抽象不应该依赖细节;细节应该依赖抽象
  • 针对接口编程,不要针对实现编程

核心思想:面向接口编程

优点

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

# coding

场景:Geely 在慕课上学习课程,学习 Java 课程,学习前端课程。

package cn.mrcode.newstudy.design.pattern.principle.dependencyinversion;

public class Geely {
    public void studyJavaCourse() {
        System.out.println("Geely 在学习 Java 课程");
    }

    public void studyFECourse() {
        System.out.println("Geely 在学习 FE 课程");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
package cn.mrcode.newstudy.design.pattern.principle.dependencyinversion;

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

1
2
3
4
5
6
7
8
9
10
Geely 在学习 Java 课程
Geely 在学习 FE 课程
1
2

现在的问题是:如果要再增加一门学习课程呢?那么解决的方案只能在 Geely 类中增加另外一门课程的方法,然后Test(应用层)再调用该方法

这破坏了_依赖倒置原则_,Test(应用层)依赖Geely(底层模块)。下面使用依赖倒置原则来进行修改

public interface ICourse {
    void studyCourse();
}
1
2
3
public class JavaCourse implements ICourse {
    @Override
    public void studyCourse() {
        System.out.println("Geely 在学习 Java 课程");
    }
}
1
2
3
4
5
6
public class FECourse implements ICourse {
    @Override
    public void studyCourse() {
        System.out.println("Geely 在学习 FE 课程");
    }
}
1
2
3
4
5
6
public class Geely {
    public void studyImoocCourse(ICourse iCourse) {
        iCourse.studyCourse();
    }
}
1
2
3
4
5
public static void main(String[] args) {
    // v1 不使用依赖倒置原则
//        Geely geely = new Geely();
//        geely.studyJavaCourse();
//        geely.studyFECourse();
//        geely.studyPythonCourse();

    Geely geely = new Geely();
    geely.studyImoocCourse(new JavaCourse());
    geely.studyImoocCourse(new FECourse());
}
1
2
3
4
5
6
7
8
9
10
11

上面这个示例:

  • geely 学习什么课程由 Test(应用层决定,高层模块)
  • 再学习其他的课程,只需要扩展课程即可。而 geely 不需要变动
    • 在底层模块扩展
    • 是扩展课程,而不是去修改已有的 JavaCourse ,这也符合了_开闭原则_
  • 面向接口编程,而不是面对 Geely
  • Test 与 Geely 是解耦的
  • Gelly 与 具体的课程实现是解耦的
  • Gelly 与 ICourse 是有依赖的
  • 所谓高内聚,低耦合,就是尽量减少耦合

这里只是一种写法,

  • 由方法参数传递进去,
  • 还可以从构造函数传递(不过这样一个 geely 实例就只能学习一种课程了)
  • 还可以设置一个set方法,每次学习前,把课程set进去
// v3
// Geely geely = new Geely(new JavaCourse());
// geely.studyImoocCourse();

Geely geely = new Geely();
geely.setCourse(new JavaCourse())
geely.studyImoocCourse();

geely.setCourse(new FECourse())
geely.studyImoocCourse();
1
2
3
4
5
6
7
8
9
10

依赖倒置原则表现了一种事实:

  • 相对于细节的多变性,抽象的东西要稳定得多
  • 以抽象搭建起来的架构,比以细节搭建起来的要稳定得多

那么抽象的目的也就是:制定好规范和契约,如 ICourse 就是一种规范契约