首页/开发/代码质量与评审速查/依赖倒置原则 DIP(Dependency Inversion Principle)
设计原则与模式62 条

依赖倒置原则 DIP(Dependency Inversion Principle)

高层策略与低层细节都依赖抽象,抽象不依赖细节(Martin 表述):在架构边界放接口,业务核心不 import 数据库与框架类型,方向感由依赖关系体现。

依赖倒置原则是什么

依赖倒置原则(Dependency Inversion Principle)由 Robert C. Martin 提出,包含两条要求:高层策略不依赖低层细节,两者都依赖抽象;抽象不依赖细节,细节依赖抽象。落地方式是端口与适配器——在架构边界定义接口,业务核心只依赖接口,数据库、消息队列、框架都退到接口实现的一侧。

基本信息

提出Robert C. Martin,SOLID 五项中的 D
两条要求高层不依赖低层;抽象不依赖细节
落地手段端口(接口)+ 适配器(实现)
收益业务逻辑可脱离基础设施独立测试与演进

典型使用场景

  • 业务层需要读写数据库:定义仓储接口,具体驱动藏在实现一侧
  • 需要替换或并存多个外部服务:支付、短信、对象存储共用同一个端口
  • 单元测试要绕开外部依赖:注入内存实现,不启动真实数据库
  • 框架升级影响面过大:业务代码不引用框架类型,升级范围收窄
  • 同一套规则被多个入口复用:API 与批处理调用同一个领域核心

依赖方向对照

依赖方向对照
// 反面:业务直接依赖具体实现
class OrderService {
    private final MySQLOrderRepository repo = new MySQLOrderRepository();
}

// 正面:接口定义在业务侧,实现反向依赖接口
interface OrderRepository { void save(Order order); }

class OrderService {
    private final OrderRepository repo;
    OrderService(OrderRepository repo) { this.repo = repo; }
}

常见误解与澄清

常见说法问题所在正确理解
用了依赖注入框架就满足 DIP框架只是注入手段,依赖方向可能依旧反的看引用方向:业务包是否引用了基础设施包
每个类都应该抽一个接口没有替换需求时只是增加跳转层级只在跨边界、需替换或需测试隔离处抽象
接口放在实现包里更顺手实现包变成被依赖方,方向没变接口定义在调用方一侧的领域包
依赖注入是手段,DIP 是原则:用了 DI 容器也可能把具体实现注入业务类,方向仍然是反的。
与六边形架构的关系:DIP 是原则,端口-适配器是它在架构层面的落地形式,Cockburn 的表述与之一致。

易错点

  • 接口定义在实现包里:核心域仍然反向依赖细节,抽象等于白加一层
  • 为每个类都加接口:没有替换需求时,只增加跳转层级与维护成本
  • 只在服务层注入接口,实体内部却直接 new 具体实现:边界被绕开
  • 把 DIP 当成依赖注入框架的别名:换了容器,依赖方向照旧

数据来源与参考

  • Robert C. Martin · DIP 论述;Alistair Cockburn 端口-适配器(六边形架构)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌