依赖倒置原则(DIP)

依赖倒置原则(DIP)

介绍

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一条重要原则,它是由罗伯特·马丁(Robert C. Martin)提出的,是“开闭原则”的基础。依赖倒置原则指导我们在编写代码时,不应该依赖具体的实现类,而应该依赖于抽象接口或抽象类,即高层模块不应该依赖低层模块,它们都应该依赖于抽象。

原则

依赖倒置原则的原则描述如下:

  1. 高层模块(例如应用程序)不应该依赖于低层模块(例如数据访问层、服务层等等),两者都应该依赖于抽象接口。
  2. 抽象接口不应该依赖于具体实现,具体实现应该依赖于抽象接口。

换句话说,依赖倒置原则强调的是针对接口编程而不是针对实现编程,具体而言就是要面向抽象编程,而不是面向具体实现编程。这样就能够减少不必要的类之间的依赖关系,提高代码的可复用性、可维护性和可扩展性。

正反案例

反例

假设我们有一个电商系统,其中包括一个订单模块和一个支付模块,它们之间的关系如下所示:

public class OrderService {
    private AliPay aliPay;

    public OrderService() {
        this.aliPay = new AliPay();
    }

    public void pay(String orderId, double amount) {
        this.aliPay.pay(orderId, amount);
    }
}

public class AliPay {
    public void pay(String orderId, double amount) {
        System.out.println("AliPay 支付订单 " + orderId + " 金额为 " + amount);
    }
}

在上面的代码中,OrderService依赖于AliPay具体实现,这违反了依赖倒置原则。如果我们想要使用其他的支付方式,比如微信支付或者银行卡支付,那么就需要修改OrderService类的代码,这显然是不符合开闭原则的。如果支付方式的种类变得越来越多,这种问题会变得越来越严重。

正例

使用依赖倒置原则,我们可以将AliPay抽象成一个接口或者一个抽象类,从而实现订单模块和支付模块的解耦。代码如下:

public interface Pay {
    void pay(String orderId, double amount);
}

public class AliPay implements Pay {
    public void pay(String orderId, double amount) {
        System.out.println("AliPay 支付订单 " + orderId + " 金额为 " + amount);
    }
}

public class OrderService {
    private Pay pay;

    public OrderService(Pay pay) {
        this.pay = pay;
    }

    public void pay(String orderId, double amount) {
        this.pay.pay(orderId, amount);
    }
}

在上面的代码中,OrderService类不再依赖于具体的支付实现,而是依赖于Pay

特点

  1. 通过抽象来降低代码间的耦合度。
  2. 提高代码的灵活性、可扩展性和可维护性。

注意事项(*重点)

  1. DIP 是面向对象设计中的基本原则,它是实现高质量软件设计的重要手段之一。
  2. 在实际应用中,DIP 通常是通过依赖注入(DI)和控制反转(IoC)等技术来实现的。
  3. 在应用 DIP 原则时,我们需要在设计之初就考虑到代码的可扩展性和可维护性,从而在代码设计和编写过程中遵循 DIP 原则。