彻底分析七大软件架构设计原则之依赖倒置原则(DIP)

本文通过实例详细解析了依赖倒置原则的概念及其在软件设计中的应用。通过对比两种设计方案,阐述了依赖倒置如何减少代码间的耦合度,提高系统的稳定性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

最近在看书的时候看到了一个很熟悉的名词,依赖倒置原则,这个对于Java开发人员来说应该都很熟悉,但是有多少人真的搞懂了这个名词的含义?网上大概搜索了一下基本上都是只有名词的定义,而不是真正的去解释这个含义,所以我决定写一篇文章分析一下这个名词的含义。如果哪里写的不对也欢迎指正和批评。

 

正文:

一:依赖倒置原则的定义

1.High-level modules should not depend onlow-level modules. Both should depend on abstractions.

2.Abstractions should not depend upondetails. Details should depend upon abstractions.

这两句话的意思是:1:高层模块不应依赖于低层模块。两者都应该依赖于抽象。2:抽象不应该依赖于细节,细节应该依赖抽象。

其实这个定义给的确实比较难以理解,要吃透这个含义还要先看一下代码。

二:不使用依赖倒置原则的设计有什么问题?

拿比较通用的驾驶员和车来做代码举例

下面的这个是建一个有C1驾照的驾驶员的类,司机可以驾驶兰博基尼汽车。(最近在考驾照有点着魔)

public class C1Driver {
    public String getDriverLicenseType(){
        return "C1";
    }

    public void drive(Lamborghini lamborghini){
        lamborghini.run();
    }
}

下面的是建一个兰博基尼汽车类

public class Lamborghini {
    public void run() {
        System.out.println("兰博基尼开始运行...");
    }
}

运行

public class Client {
    public static void main(String[] args) {
        C1Driver zhangsan = new C1Driver();
        zhangsan.drive(new Lamborghini());
    }
}

上面的这段代码对于司机张三驾驶他的兰博基尼一点问题都没有,那么当张三想买辆宝马开着玩玩怎么办呢?

对于上面的实现来说,就只能从高层模块(调用端)开始改起。C1驾驶员类改为

public class C1Driver {
    public String getDriverLicenseType(){
        return "C1";
    }

    public void drive(Lamborghini lamborghini){
        lamborghini.run();
    }

    public void drive(BMW bmw){
        bmw.run();
    }
}

(底层模块)被调用端新建一个宝马的汽车类

public class BMW {
    public void run() {
        System.out.println("宝马开始运行...");
    }
}
public static void main(String[] args) {
        C1Driver zhangsan = new C1Driver();
        zhangsan.drive(new BMW());
    }

这样虽然实现了张三驾驶宝马车的愿望,那么问题又来了,李四也想开宝马,但是他只有C2的驾照,怎么办呢,只能继续新建一个C2驾照的司机类,然后调用BMW的汽车类,这里就不做代码展示了,通过上面这段代码可以看出,这种实现方式极其的糟糕和不稳定,稍有变动全局都要改一遍,那么针对这种问题架构设计上注意的原则是什么呢?那就是依赖倒置原则,这也是面向接口编程的精髓和基础原则。

三:何为依赖倒置?

上面讲了依赖倒置的定义和不遵守依赖倒置原则产生的问题,那么到底依赖倒置是什么意思?

用上面的代码做类图进行分析

如果所示,C1驾驶员类的实现依赖于汽车类兰博基尼的实现,这个就是依赖正置,就是实现依赖实现,按照直接思考的顺序来说,我有C1驾照我也有兰博基尼我就可以开。

按照依赖倒置的定义来分析

如图可见,C1Driver和C2Driver都共同实现了一个IDriver的抽象,同样两个汽车类也都共同依赖了一个ICar汽车类的抽象,在这种设计下,当张三又想开奔驰了,新建一个奔驰类即可。李四也想开车,新建一个C2驾照的实现类即可。

按照依赖倒置原则设计的代码如下:

司机类:

public interface IDriver {
    String getDriverLicenseType();
    void drive(ICar car);
}
public class C1Driver implements IDriver{
    public String getDriverLicenseType(){
        return "C1";
    }

    public void drive(ICar iCar){
        iCar.run();
    }
}
public class C2Driver implements IDriver{
    public String getDriverLicenseType(){
        return "C2";
    }

    public void drive(ICar iCar){
        iCar.run();
    }

}

汽车类:

public interface ICar {
    void run();
}

public class BMW implements ICar{
    public void run() {
        System.out.println("宝马开始运行...");
    }
}
public class Lamborghini implements ICar{
    public void run() {
        System.out.println("兰博基尼开始运行...");
    }
}

运行

public class Client {
    public static void main(String[] args) {
        IDriver zhangsan = new C1Driver();
        zhangsan.drive(new BMW());
        zhangsan.drive(new Lamborghini());

        IDriver lisi = new C2Driver();
        lisi.drive(new BMW());
        lisi.drive(new Lamborghini());
    }
}

根据上面的类图和实现可以看出,依赖倒置实际的含义就是原本由实现类和实现类之间的依赖,倒置为相关的实现类所继承的父类或者所实现的接口之间的依赖。

通过依赖倒置,可以有效的降低类与类之间的耦合度,提高系统的稳定性,提高代码的可维护性,同时也降低了因为需求变更带来的修改代码的风险。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值