【设计模式】设计原则:DIP 依赖倒置原则

本文介绍了依赖倒置原则(DIP),并通过一个学习课程的例子展示了如何应用这一原则重构代码,以减少类间耦合,提高代码可维护性。同时对比了控制反转、依赖注入等概念。

依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节;细节应该依赖抽象。

通过依赖倒置,可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并能够降低修改程序所造成的风险。

1.初始版本

接下来看一个案例,还是以课程为例,先来创建一个类 Jack:

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

来调用一下:

public static void main(String[] args) {
    Jack jack = new Jack();
    jack.studyJavaCourse();
    jack.studyPythonCourse();
}

2.代码重构

Tom 热爱学习,目前正在学习 Java 课程和 Python 课程。大家都知道,学习也是会上瘾的。随着学习兴趣的暴涨,现在 Tom 还想学习 AI 人工智能的课程。

这个时候,业务扩展,我们的代码要从底层到高层(调用层)一次修改代码。在 Tom 类中增加 studyAICourse()的方法,在高层也要追加调用。如此一来,系统发布以后,实际上是非常不稳定的,在修改代码的同时也会带来意想不到的风险。

接下来我们优化代码,创建一个课程的抽象 ICourse 接口:

public interface ICourse {
	void study();
}

然后写 JavaCourse 类

public class JavaCourse implements ICourse {
    @Override
    public void study() {
   	 	System.out.println("Jack 在学习 Java 课程");
    }
}

再实现 PythonCourse 类:

public class PythonCourse implements ICourse {
    @Override
    public void study() {
    	System.out.println("Tom 在学习 Python 课程");
    }
}

修改 Jack 类

public class Jack {
    public void study(ICourse course){
    	course.study();
    }
}

来看调用:

public static void main(String[] args) {
    Jack jack = new Jack();
    jack.study(new JavaCourse());
    jack.study(new PythonCourse());
}

我们这时候再看来代码,Jack 的兴趣无论怎么暴涨,对于新的课程,我只需要新建一个类,通过传参的方式告诉 Jack,而不需要修改底层代码。

public class AICourse implements ICourse {
    @Override
    public void study() {
        System.out.println("Jack 在学习 AI 课程");
    }
}

现在我们再来看最终的类图:

在这里插入图片描述

3.几个概念比较

1)控制反转

实际上,控制反转是一个比较笼统的设计思想,并不是一种具体的实现方法,一般用来指导框架层面的设计。这里所说的“控制”指的是对程序执行流程的控制,而“反转”指的是在没有使用框架之前,程序员自己控制整个程序的执行。在使用框架之后,整个程序的执行流程通过框架来控制。流程的控制权从程序员“反转”给了框架。

2)依赖注入

依赖注入和控制反转恰恰相反,它是一种具体的编码技巧。我们不通过 new 的方式在类内部创建依赖类的对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类来使用。这样就提高了代码的扩展性,我们可以灵活地替换依赖的类,也可以认为是开闭原则的一种实现。

3)依赖注入框架

我们通过依赖注入框架提供的扩展点,简单配置一下所有需要的类及其类与类之间依赖关系,就可以实现由框架来自动创建对象、管理对象的生命周期、依赖注入等原本需要程序员来做的事情。

4)依赖反转原则

依赖反转原则也叫作依赖倒置原则。这条原则跟控制反转有点类似,也是一种设计思想,主要用来指导框架层面的设计。高层模块不依赖低层模块,它们共同依赖同一个抽象。抽象不要依赖具体实现细节,具体实现细节依赖抽象。

我们再来拿 Tomcat 这个 Servlet 容器作为例子来解释一下。Tomcat 是运行 Java Web 应用程序的容器。我们编写的 Web 应用程序代码只需要部署在 Tomcat 容器下,便可以被 Tomcat 容器调用执行。按照之前的划分原则,Tomcat 就是高层模块,我们编写的 Web 应用程序代码就是低层模块。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Sevlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet规范。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A minor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值