依赖倒置原则要求高层与低层模块均依赖抽象,抽象不依赖细节;关键在于定义窄而稳定的接口或抽象类,通过依赖注入解耦具体实现,实现高聚合、易测试与可扩展。

依赖倒置原则(DIP)的核心是让高层模块不依赖低层模块,二者都依赖抽象;抽象不依赖细节,细节依赖抽象。要写出“只依赖抽象类”的高聚合代码,关键不是回避具体实现,而是把依赖关系锚定在稳定、窄接口的抽象上,同时确保每个类职责聚焦、协作清晰。
定义窄而稳定的抽象类或接口
抽象不是越“大”越好,而是要精准表达协作契约。避免定义包含大量无关方法的基类,优先用接口(interface)或抽象类(abstract class)声明最小必要行为。
- 例如:一个订单服务不需要知道支付是走微信还是支付宝,只需依赖 IPaymentProcessor 接口,它只含 Process(amount) 和 Refund(id) 两个方法
- 抽象类若需共享默认逻辑(如日志模板、重试机制),可提供 protected 方法,但公开契约仍应精简
- 命名体现意图而非技术实现,如 IInventoryChecker 比 IDatabaseService 更符合 DIP 精神
构造时注入具体实现,运行时隔离细节
具体类的创建和组装交给外部(如工厂、DI 容器),业务类内部只持有抽象引用,不 new、不 import 具体类型。
- 订单服务类的构造函数参数为 IPaymentProcessor 和 IInventoryChecker,不出现 WechatPayment 或 RedisInventory
- 避免在方法体内条件判断后 new 具体类(如 if (type == “wechat”) new WechatPayment()),这会硬编码依赖
- 可通过策略模式+配置驱动选择实现,但选择逻辑本身也应抽象(如 IPaymentStrategySelector)
聚合通过抽象协作,而非继承或强耦合调用
高聚合指功能内聚、边界清晰,类之间靠抽象契约交互,彼此不知对方内部结构。这不是“不用 new”,而是“不依赖具体形态”。
- 一个订单聚合根(Order)可协调 Payment、Inventory、Notification,但它持有的全是接口实例,不关心它们是否单例、是否远程、是否带缓存
- 避免抽象类中直接调用具体子类方法,也不在抽象里暴露 protected 字段供子类篡改状态
- 聚合内的对象生命周期由外部统一管理(如 DI 容器),而非在某个类里 new 出一堆具体对象再传参
测试与演进:抽象即契约,实现可替换
当所有依赖都是抽象,单元测试天然解耦——用 Mock 替换真实实现,无需启动数据库或调用第三方 API。
- 写测试时,只需 mock IPaymentProcessor 的返回值,就能完整验证订单提交逻辑
- 新增支付方式(如 Apple Pay)只需新增实现类并注册到容器,零修改现有业务代码
- 如果发现某个抽象频繁修改,说明契约设计过宽或职责不清,应回头重构抽象,而非妥协加字段
不复杂但容易忽略:DIP 不是消灭具体类,而是把“谁来创建”和“如何协作”分清楚。抽象是协作的协议,不是父类的包袱。











