依赖倒转原则是 SOLID 五大设计原则之一,由 Robert C. Martin 提出。它本质上是“颠倒”传统依赖关系的方向:传统设计中,高层模块(如业务逻辑)往往直接依赖低层模块(如具体工具或服务),这会导致代码僵硬、难以维护。DIP 要求高层模块和低层模块都依赖抽象层,从而实现“倒转”——抽象成为桥梁,让系统更灵活。

核心思想:从“具体依赖具体”到“抽象依赖具体”
  • 传统问题:高层模块(如订单处理)直接调用低层模块(如具体数据库),如果低层变化(如换数据库),高层必须重写。
  • DIP 解决方案:引入抽象(接口或抽象类),高层只依赖抽象,低层实现抽象。这样,高层“不知道”低层的细节,只通过抽象“说话”。
两条规则
  1. 高层模块不应依赖低层模块:高层应依赖抽象,低层也依赖同一抽象。
  2. 抽象不应依赖细节:抽象定义“契约”(方法签名),细节(实现)适应契约。
为什么需要它?(益处视角)
  • 解耦与复用:像乐高积木,组件可替换而不影响整体。
  • 测试友好:用假对象(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 自动注入;结合工厂模式动态选择实现。
  • 常见误区:抽象别太宽(违背接口隔离原则),保持单一职责。

这个解释从支付场景切入,强调“倒转”的动态性。

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐