介绍
依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一条重要原则,它是由罗伯特·马丁(Robert C. Martin)提出的,是“开闭原则”的基础。依赖倒置原则指导我们在编写代码时,不应该依赖具体的实现类,而应该依赖于抽象接口或抽象类,即高层模块不应该依赖低层模块,它们都应该依赖于抽象。
原则
依赖倒置原则的原则描述如下:
- 高层模块(例如应用程序)不应该依赖于低层模块(例如数据访问层、服务层等等),两者都应该依赖于抽象接口。
- 抽象接口不应该依赖于具体实现,具体实现应该依赖于抽象接口。
换句话说,依赖倒置原则强调的是针对接口编程而不是针对实现编程,具体而言就是要面向抽象编程,而不是面向具体实现编程。这样就能够减少不必要的类之间的依赖关系,提高代码的可复用性、可维护性和可扩展性。
正反案例
反例
假设我们有一个电商系统,其中包括一个订单模块和一个支付模块,它们之间的关系如下所示:
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
特点
- 通过抽象来降低代码间的耦合度。
- 提高代码的灵活性、可扩展性和可维护性。
注意事项(*
重点)
- DIP 是面向对象设计中的基本原则,它是实现高质量软件设计的重要手段之一。
- 在实际应用中,DIP 通常是通过依赖注入(DI)和控制反转(IoC)等技术来实现的。
- 在应用 DIP 原则时,我们需要在设计之初就考虑到代码的可扩展性和可维护性,从而在代码设计和编写过程中遵循 DIP 原则。