跳转至

依赖倒转原则

约 691 个字 15 行代码 1 张图片 预计阅读时间 4 分钟

场景:电话遥控修电脑

娇娇电脑蓝屏,小菜通过电话指导她 拔一根内存条 排查故障——用户无需懂 CPU 如何制造,只需懂 标准接口(内存插槽)。PC 硬件的 易插拔 正是 依赖倒转 的生动类比。

原则定义

依赖倒转原则(Dependency Inversion Principle,DIP):

  1. 高层模块不应该依赖低层模块,二者都应该依赖抽象。
  2. 抽象不应该依赖细节,细节应该依赖抽象。

白话:针对接口编程,不要针对实现编程。

主板、CPU、内存、硬盘都 针对接口(插槽/针脚标准) 设计;若内存必须绑定某品牌主板,换内存就要换主板——显然不合理。

为何叫「倒转」

面向过程时代:高层直接调用底层函数库(如访问数据库的函数),高层依赖低层

面向对象时代:高层与低层都依赖 抽象接口,依赖方向 倒转 了——细节(MySQL 驱动、PostgreSQL 驱动)依赖抽象(Connection 接口)。

与 PC 硬件的类比

概念 软件
CPU 强内聚、标准接口 类封装内部实现,对外暴露稳定 API
内存坏了只换内存 模块可独立替换,不影响其他部件
主板预留插槽 依赖抽象,而非具体实现

里氏代换原则(LSP)

DIP 常与 里氏代换原则 一起理解:

子类型必须能够替换掉它们的父类型。 程序中使用父类的地方,换成子类后行为应仍然正确。

反例:鸟会飞,企鹅不会飞——在 编程世界 里企鹅不应继承「鸟」;应抽象出 Flyable 等更精确的接口。

简单对比

Java
// 违反 DIP:高层直接依赖具体 JDBC
class ReportService {
    void export() {
        MySqlReportExporter ex = new MySqlReportExporter();
        ex.run();
    }
}

// 更符合 DIP
interface ReportExporter { void run(); }
class ReportService {
    private final ReportExporter exporter;
    ReportService(ReportExporter exporter) { this.exporter = exporter; }
    void export() { exporter.run(); }
}

依赖注入(DI) 是实现 DIP 的常用手段:构造器注入、Setter 注入、IoC 容器等。

SOLID 中的位置

字母 原则 与 DIP 关系
S 单一职责 职责清晰才易抽象
O 开放-封闭 扩展通过新实现接入
L 里氏代换 保证多态替换安全
I 接口隔离 小接口降低依赖面
D 依赖倒转 依赖方向指向抽象

小结

PC 硬件发展与面向对象思想 异曲同工:都通过 标准接口 实现 强内聚、松耦合。依赖倒转让高层逻辑与基础设施解耦,是工厂、抽象工厂、策略等模式共同的理论基础。

评论