DDD | 依赖倒置到底是个啥?真的有必要吗?
2026/5/12 22:40:44 网站建设 项目流程

关注我的公众号,获取独家技术分享和资料

一、先讲个故事:老王开饭店

老王开了一家饭店,雇了个厨师叫小李。

最初的做法(直接依赖):

老王的饭店所有菜单、流程、采购都是围绕小李来设计的。

小李喜欢用铁锅,老王就买铁锅;小李习惯早上8点到,老王就8点开门。

问题来了:

  • 小李要回老家了,饭店怎么办?

  • 找个新厨师小张,但小张用不惯铁锅,喜欢用不粘锅...

  • 老王不得不把厨房重新装修一遍!

这就是直接依赖带来的问题:高层(饭店)被低层(具体的厨师)绑架了


二、依赖倒置是怎么解决的?

老王学聪明了,他定了一个"厨师岗位规范":

规范里写着:

  • 必须会做本店菜单上的菜

  • 早上7:30到岗

  • 会用店里提供的标准厨具

现在,不管是小李、小张还是小王,只要符合这个规范,都能来老王店里上班。老王的饭店不再依赖某个具体的厨师,而是依赖于一个抽象的规范

这就是依赖倒置的核心思想:

高层模块不应该依赖低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

用人话说就是:老板别盯着具体的人,要盯着岗位说明书


三、代码世界里的依赖倒置

错误示范:直接依赖

// 订单服务直接依赖MySQL public class OrderService { private MySQLOrderRepository repository = new MySQLOrderRepository(); public void createOrder(Order order) { repository.save(order); } }

问题:哪天老板说要换成 PostgreSQL,你得改 OrderService;要换成 MongoDB?再改一遍...

正确示范:依赖倒置

// 定义抽象(接口) publicinterface OrderRepository { void save(Order order); } // 高层模块依赖抽象 publicclass OrderService { private OrderRepository repository; // 依赖接口,不依赖具体实现 public OrderService(OrderRepository repository) { this.repository = repository; } public void createOrder(Order order) { repository.save(order); } } // 具体实现也依赖抽象 publicclass MySQLOrderRepository implements OrderRepository { public void save(Order order) { /* MySQL实现 */ } } publicclass MongoOrderRepository implements OrderRepository { public void save(Order order) { /* MongoDB实现 */ } }

现在换数据库?只需要:

// 用MySQL OrderService service = new OrderService(new MySQLOrderRepository()); // 换MongoDB OrderService service = new OrderService(new MongoOrderRepository());

OrderService 一行代码都不用改!


四、在DDD中,依赖倒置有多重要?

在领域驱动设计(DDD)中,依赖倒置简直是灵魂级别的存在。

DDD的分层架构

┌─────────────────────────────────────┐ │ 用户接口层 │ ├─────────────────────────────────────┤ │ 应用服务层 │ ├─────────────────────────────────────┤ │ ★ 领域层(核心业务逻辑)★ │ ← 这是老大! ├─────────────────────────────────────┤ │ 基础设施层 │ ← 数据库、消息队列、第三方服务等 └─────────────────────────────────────┘

传统做法的问题:

领域层要存订单,直接调用基础设施层的 MySQLRepository。结果呢?

  • 核心业务代码里混入了数据库操作细节

  • 想换个存储方案?业务代码全得改

  • 写单元测试?先给我起个数据库再说...

依赖倒置后:

领域层定义: interface OrderRepository { save(order); } 基础设施层实现: class MySQLOrderRepository implements OrderRepository
  • 领域层只关心"我需要能存订单"这个能力

  • 至于用MySQL还是Redis,领域层根本不care

  • 测试时换个内存实现就行,秒测

这才是DDD要的效果:让领域模型成为真正的核心,不被技术细节污染。


五、依赖倒置是必须的吗?

说实话,不是

什么时候可以不用?

  1. 简单的CRUD项目

    • 就是增删改查,业务逻辑简单

    • 数据库基本不可能换

    • 团队就两三个人,沟通成本低

  2. 一次性项目

    • 临时性的工具脚本

    • 用完即弃的演示项目

  3. 性能极致要求

    • 某些场景抽象层会带来微小开销

    • 但说实话,99%的项目瓶颈不在这

什么时候必须用?

  1. 业务复杂度高的系统

    • 电商、金融、供应链等

    • 业务规则多,变化快

  2. 需要长期维护的项目

    • 预期生命周期3年以上

    • 团队会不断更换

  3. 有明确的技术选型不确定性

    • 今天用MySQL,明天可能要迁移

    • 今天用短信验证码,明天可能换人脸识别

  4. 需要高质量测试覆盖

    • 没有依赖倒置,很多单元测试根本写不了


六、依赖倒置的代价

既然依赖倒置有那么多好处,那有哪些代价呢:

代价

说明

代码量增加

多了接口、多了注入逻辑

理解成本

初级开发者可能绕晕

过度设计风险

简单问题复杂化

调试困难

依赖关系不够直观

架构师的价值就在于:在正确的场景做正确的选择。


七、总结

一句话总结依赖倒置

别让你的核心业务代码依赖具体的技术实现,而是让技术实现来适配你的业务需求。

形象比喻

  • USB接口:电脑不关心你插的是鼠标还是键盘,只要符合USB规范

  • 220V插座:插座不关心你接的是电视还是冰箱,只要是220V的插头

  • 招聘JD:公司不关心谁来应聘,只要符合岗位要求

最终建议

依赖倒置不是银弹,但在中大型项目、复杂业务场景、长期维护的系统中,它几乎是必选项


📝记住:好的架构不是一开始就完美的,而是在正确的时机做出正确的权衡。依赖倒置只是工具而已。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询