首页/开发/系统分析与架构设计速查/依赖倒置原则(DIP)
架构风格与模式58 条

依赖倒置原则(DIP)

高层模块与低层模块都依赖抽象;抽象不依赖细节,细节依赖抽象。它约束的是依赖方向,常被与依赖注入(一种实现手段)混为一谈。

依赖倒置是什么

依赖倒置原则规定:高层模块与低层模块都依赖抽象,抽象不依赖细节,细节依赖抽象。它约束的是依赖方向,而不是依赖如何传入——后者是依赖注入,属于实现手段。两者常被混为一谈,导致引入了注入容器却依然把框架类型散布在业务代码里。

落地标志

判断是否真的做到了依赖倒置,看业务核心包的 import 列表:不出现框架、数据库驱动与 HTTP 客户端类型。此时核心用例可以用内存实现直接跑单元测试,不需要启动容器与数据库,替换外部依赖也不必改动业务代码。

基本信息

与依赖注入的区别依赖倒置是设计原则;依赖注入是把依赖从外部传入的实现方式
接口归属接口定义在需要它的模块一侧,由外层适配器实现
收益核心逻辑可独立测试,外部实现可替换
常见误用按实现类逐方法生成接口,抽象没有业务含义

依赖方向示例

依赖方向示例
# 业务核心模块:定义接口,不引入任何框架类型
interface OrderRepository { Order findById(OrderId id); }

class PlaceOrderService {
    private final OrderRepository repo;    # 构造注入
    PlaceOrderService(OrderRepository repo) { this.repo = repo; }
}

# 外层适配器模块:实现接口,依赖方向指向业务核心
class MysqlOrderRepository implements OrderRepository { ... }

检查与演练

  • 检查业务包 import:不出现框架、驱动与 HTTP 客户端类型
  • 替换演练:注入内存实现跑单测,验证核心逻辑与外层解耦
  • 依赖方向:适配器依赖核心,核心不反向依赖适配器
  • 接口粒度:按业务用例命名,而不是按数据表或框架方法命名

常见误用

把依赖注入框架当作依赖倒置的完成标志,是最常见的误用:容器帮你装配实现,但业务代码里仍然到处出现具体框架类型时,依赖方向没有改变。另一种误用是给每个类都配一个接口,接口与实现一比一对应,抽象没有承担任何业务含义,只增加了阅读与重构成本。

把接口定义在需要它的模块一侧(向内),由外层适配器实现,抽象就不会跟着外部技术变化。这也是端口与适配器结构的核心约定。

易错点

  • 接口按实现类逐方法生成,抽象没有任何业务含义,只是多了一层转发
  • 只把依赖注入容器引入却没有反转依赖方向,框架类型仍遍布业务代码
  • 核心模块直接依赖具体驱动类型,更换存储时必须改动业务逻辑
  • 为每个类都创建接口,接口数量膨胀,阅读成本远高于收益

数据来源与参考

  • Robert C. Martin《Clean Architecture》
  • Martin Fowler bliki《Inversion of Control》
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌