后端技术面试 38 讲
李智慧
同程艺龙交通首席架构师,前 Intel& 阿里架构师,《大型网站技术架构》作者
37373 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 46 讲
不定期加餐 (1讲)
后端技术面试 38 讲
15
15
1.0x
00:00/00:00
登录|注册

12 | 软件设计的依赖倒置原则:如何不依赖代码却可以复用它的功能?

不要来调用我,我会调用你
抽象接口的所有权倒置
重构设计为依赖于抽象
高层模块定义接口,低层模块实现接口
解决办法:每个高层模块为所需服务声明一个抽象接口
复用困难性
维护困难性
抽象不应该依赖具体实现,具体实现应该依赖抽象
高层模块不应该依赖低层模块,二者都应该依赖抽象
无需在程序中调用框架的代码,就可以使用框架的功能特性
底层模块和高层模块共同依赖的抽象
软件设计遵循依赖倒置原则的例子
软件开发中的应用
典型使用场景:框架的设计
遵循依赖倒置原则的编码守则
好莱坞原则
依赖于抽象
接口所有权的倒置
传递依赖问题
依赖倒置原则的优点
依赖倒置原则
框架的特点
思考题
小结
使用依赖倒置实现高层模块复用
依赖倒置的关键是接口所有权的倒置
软件开发中的依赖倒置原则
软件设计的依赖倒置原则

该思维导图由 AI 生成,仅供参考

在软件开发过程中,我们经常会使用各种编程框架。如果你使用的是 Java,那么你会比较熟悉 Spring、MyBatis 等。事实上,Tomcat、Jetty 这类 Web 容器也可以归类为框架。框架的一个特点是,当开发者使用框架开发一个应用程序时,无需在程序中调用框架的代码,就可以使用框架的功能特性。比如程序不需要调用 Spring 的代码,就可以使用 Spring 的依赖注入,MVC 这些特性,开发出低耦合、高内聚的应用代码。我们的程序更不需要调用 Tomcat 的代码,就可以监听 HTTP 协议端口,处理 HTTP 请求。
这些框架我们每天都在使用,已经司空见惯,所以觉得这种实现理所当然,但是我们停下好好想一想,难道不觉得这很神奇吗?我们自己也写代码,能够做到让其他工程师不调用我们的代码就可以使用我们的代码的功能特性吗?就我观察,大多数开发者是做不到的。那么 Spring、Tomcat 这些框架是如何做到的呢?

依赖倒置原则

我们看下 Spring、Tomcat 这些框架设计的核心关键点,也就是面向对象的基本设计原则之一:依赖倒置原则。
依赖倒置原则是这样的:
高层模块不应该依赖低层模块,二者都应该依赖抽象。
抽象不应该依赖具体实现,具体实现应该依赖抽象。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

依赖倒置原则是软件设计中的重要原则之一,它要求高层模块不应该依赖于低层模块,而是二者都应该依赖于抽象。这一原则的应用能够帮助开发者开发出更少依赖、更低耦合、更可复用的代码。文章通过介绍Spring、Tomcat等框架的设计原则和依赖倒置的关键点,阐述了依赖倒置原则的设计原理和在程序设计开发中的应用。通过倒置接口所有权,高层模块定义接口,低层模块实现接口,实现了依赖关系的倒置。这种设计方式使得高层模块不依赖低层模块,低层模块的改动不会影响高层模块,同时也实现了高层模块的复用不依赖低层模块。依赖倒置原则的典型使用场景是框架的设计,框架提供一组接口规范,应用程序只需要遵循接口规范编程,就可以被框架调用,从而提高了框架的可复用性。遵循依赖倒置原则的软件设计能够帮助开发者开发出灵活、低耦合、可复用的软件代码。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《后端技术面试 38 讲》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(47)

  • 最新
  • 精选
  • 山猫
    依赖倒置这个东西懂得人是真懂,不懂的人是一点不懂。当初为了搞懂依赖倒置原则花了相当长时间去阅读大量的文章和书籍,看了很多代码事例,后来又看了面对对象设计原则才算基本理解。 之前给公司开发培训,他们仍旧听的一脸懵逼,觉得这是个噱头。直到我跟他们说:老板就是找个写代码的人,别把自己看的那么重。你们每天写那么多bug,别怪老板说要换人。他们才理解!

    作者回复: 这个解释精彩😁

    2019-12-18
    10
    66
  • 唐二毛
    疑问: 按照我的理解,上层定义接口,对应到项目(传统三层架构),就是controller 层定义 service 层的接口,service层定义 dao层的接口,是这样吗? DI的目的是减少功能变化时,对代码的修改,可是我发现一旦这么做的时候,不但不能减少,反而会增加,因为功能的变化一般都是最上层的变化,比如: 参数的增加,减少,参数中字段的增加,减少,修改,这样的每一个变化都会影响到每一层的接口,所以在每一次功能变化的时候,都需要将整个调用链路的代码修改。 如果每层之间都加了防腐层,那每次变化都陷入到繁琐的改字段,测试字段之中。所有的unit test也要跟着变。这样真就是完完全全的牵一发而动全身! 有时我甚至觉得,把一个功能缩在一个类中,反而会更简单! 希望老师务必解答我的疑问,这个问题困扰我很久了!

    作者回复: 首先,依赖倒置后Service定义接口,DAO实现接口,不会导致变化更频繁,至少不会比原来DAO定义接口更频繁,因为从纯粹代码角度看,这个接口所有权的变化,换汤不换药,跟以前一样的。当然建议你用DDD的一些设计思路去设计服务和仓储,才能真正体现依赖倒置的优势,设计更稳定。 其次,即使仅仅换汤不换药,也可以强迫设计者从Service的角度去设计接口,而不是从DAO角度设计接口,从而使接口的设计更加符合业务特点。

    2019-12-19
    3
    16
  • 高层模块和底层模块是依据什么划分的?

    作者回复: 根据调用关系,高层模块调用低层模块。即使是设计的时候依赖关系被倒置了,调用的时候也还是高层调用低层。

    2019-12-18
    6
  • 池渊
    怎么觉得依赖倒置和面向接口编程说的是同一个东西,是哪里理解有误吗?老师帮解答下

    作者回复: 依赖倒置强调:接口使用者定义接口,而不是接口实现者定义接口。 面向接口编程的概念比较泛,通常不强调接口是谁定义的。

    2020-02-05
    2
  • QQ怪
    懂了懂了,看了3遍,听了3遍,基本理解,但是也不能太刻板的认为一定得是高层定义接口吧,只要都依赖抽象感觉就行了,不需要太计较这个抽象层在哪吧

    作者回复: 👍 建议看完模块二再回头看一遍,要计较的😁

    2019-12-30
    2
    1
  • 飞翔
    老师 想问一下依赖倒置 和普通接口 底层模块自己定义接口 什么时候用依赖倒置 什么时候用普通接口呀

    作者回复: 通常情况,如果可以,尽量用依赖倒置。 开发框架的时候必须用依赖倒置。

    2023-03-20归属地:美国
  • 惘 闻
    spring的依赖注入也是控制反转.从应用程序new Bean()变为给这段应用程序注入一个Bean,将Bean的获取由程序new变为框架注入.原本是应用程序控制具体的Bean,现在变为了Bean控制应用程序???? 头大 想不明白啊. 但是倒是符合程序不new Bean,Bean去自动注入程序.也就是好莱坞原则.

    作者回复: Bean没有控制程序,是框架控制。

    2021-02-18
  • 席席
    李老师,既然依赖倒置设计原则是高层模块抽象接口,低层模块实现接口,那么为什么web项目中还要在service层抽象接口,然后再用接口调用低层Dao呢,是否多此一举?

    作者回复: service调用Dao接口是反依赖倒置原则的

    2020-06-30
    2
  • leslykay
    Lamp实现ButtonServer的那个UML图,是不是要改成虚线加空心三角形?

    作者回复: 从UML的语法应该虚线,实践中继承和泛化我一般没做区分,就是我在UML一篇提到的UML方言,不影响交流即可。

    2020-02-09
  • 虢國技醬
    看了这几篇我感觉:接口这种类型非常重要;接口定义的好坏代表了我们是否对一类操作“抽象”的恰当。

    作者回复: 是的

    2020-01-21
收起评论
显示
设置
留言
47
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部