一天一个设计模式—— 依赖倒转原则
·
依赖倒转原则是 SOLID 五大设计原则之一,由 Robert C. Martin 提出。它本质上是“颠倒”传统依赖关系的方向:传统设计中,高层模块(如业务逻辑)往往直接依赖低层模块(如具体工具或服务),这会导致代码僵硬、难以维护。DIP 要求高层模块和低层模块都依赖抽象层,从而实现“倒转”——抽象成为桥梁,让系统更灵活。
核心思想:从“具体依赖具体”到“抽象依赖具体”
- 传统问题:高层模块(如订单处理)直接调用低层模块(如具体数据库),如果低层变化(如换数据库),高层必须重写。
- DIP 解决方案:引入抽象(接口或抽象类),高层只依赖抽象,低层实现抽象。这样,高层“不知道”低层的细节,只通过抽象“说话”。
两条规则
- 高层模块不应依赖低层模块:高层应依赖抽象,低层也依赖同一抽象。
- 抽象不应依赖细节:抽象定义“契约”(方法签名),细节(实现)适应契约。
为什么需要它?(益处视角)
- 解耦与复用:像乐高积木,组件可替换而不影响整体。
- 测试友好:用假对象(Mock)模拟依赖,快速验证高层逻辑。
- 扩展性:支持“开闭原则”(对扩展开放,对修改关闭),易于添加新实现。
- 实际场景:在微服务或大型项目中,避免“意大利面条式”代码。
新示例:支付系统(Java 实现)
假设一个 OrderService(高层)需要处理支付。如果直接依赖具体支付方式(如支付宝),就违反 DIP。我们用支付接口“倒转”依赖。
违反 DIP 的坏示例:
// 低层:具体支付实现
class AlipayPayment {
public boolean pay(double amount) {
System.out.println("支付宝支付 " + amount);
return true; // 模拟成功
}
}
// 高层:直接依赖低层
class OrderService {
private AlipayPayment payment;
public OrderService() {
this.payment = new AlipayPayment(); // 硬编码耦合
}
public void processOrder(double amount) {
if (payment.pay(amount)) {
System.out.println("订单支付成功");
}
}
}
问题:想加微信支付?必须改 OrderService。
符合 DIP 的好示例:
// 简单数据模型
class Order {
private double amount;
public Order(double amount) { this.amount = amount; }
public double getAmount() { return amount; }
}
// 抽象层:支付接口
interface PaymentProcessor {
boolean pay(Order order);
}
// 低层:支付宝实现
class AlipayPayment implements PaymentProcessor {
@Override
public boolean pay(Order order) {
System.out.println("支付宝支付 " + order.getAmount());
return true;
}
}
// 低层:微信实现
class WeChatPayment implements PaymentProcessor {
@Override
public boolean pay(Order order) {
System.out.println("微信支付 " + order.getAmount());
return true;
}
}
// 高层:依赖抽象
class OrderService {
private PaymentProcessor processor;
// 依赖注入:外部传入抽象
public OrderService(PaymentProcessor processor) {
this.processor = processor;
}
public void processOrder(Order order) {
if (processor.pay(order)) {
System.out.println("订单支付成功");
}
}
}
// 使用示例
public class Main {
public static void main(String[] args) {
// 用支付宝
Order order1 = new Order(100.0);
OrderService service1 = new OrderService(new AlipayPayment());
service1.processOrder(order1); // 输出: 支付宝支付 100.0 \n 订单支付成功
// 切换微信,无需改 OrderService
Order order2 = new Order(200.0);
OrderService service2 = new OrderService(new WeChatPayment());
service2.processOrder(order2); // 输出: 微信支付 200.0 \n 订单支付成功
}
}
在这里,OrderService 只“关心”支付接口,不在乎是支付宝还是微信。未来加 Apple Pay?只需新实现接口即可。
实践Tips
- 何时应用:设计新系统时,先画接口图。
- 工具支持:Java 用 Spring 的
@Autowired自动注入;结合工厂模式动态选择实现。 - 常见误区:抽象别太宽(违背接口隔离原则),保持单一职责。
这个解释从支付场景切入,强调“倒转”的动态性。
更多推荐
所有评论(0)