设计模式之美
王争
前Google工程师,《数据结构与算法之美》专栏作者
立即订阅
17714 人已学习
课程目录
已更新 22 讲 / 共 100 讲
0/6登录后,你可以任选6讲全文学习。
开篇词 (1讲)
开篇词 | 一对一的设计与编码集训,让你告别没有成长的烂代码!
免费
设计模式学习导读 (3讲)
01 | 为什么说每个程序员都要尽早地学习并掌握设计模式相关知识?
02 | 从哪些维度评判代码质量的好坏?如何具备写出高质量代码的能力?
03 | 面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
设计原则与思想:面向对象 (11讲)
04 | 理论一:当谈论面向对象的时候,我们到底在谈论什么?
05 | 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?
06 | 理论三:面向对象相比面向过程有哪些优势?面向过程真的过时了吗?
07 | 理论四:哪些代码设计看似是面向对象,实际是面向过程的?
08 | 理论五:接口vs抽象类的区别?如何用普通的类模拟抽象类和接口?
09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?
10 | 理论七:为何说要多用组合少用继承?如何决定该用组合还是继承?
11 | 实战一(上):业务开发常用的基于贫血模型的MVC架构违背OOP吗?
12 | 实战一(下):如何利用基于充血模型的DDD开发一个虚拟钱包系统?
13 | 实战二(上):如何对接口鉴权这样一个功能开发做面向对象分析?
14 | 实战二(下):如何利用面向对象设计和编程开发接口鉴权功能?
设计原则与思想:设计原则 (5讲)
15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?
16 | 理论二:如何做到“对扩展开放、修改关闭”?扩展和修改各指什么?
17 | 理论三:里式替换(LSP)跟多态有何区别?哪些代码违背了LSP?
18 | 理论四:接口隔离原则有哪三种应用?原则中的“接口”该如何理解?
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
不定期加餐 (2讲)
加餐一 | 用一篇文章带你了解专栏中用到的所有Java语法
加餐二 | 设计模式、重构、编程规范等相关书籍推荐
设计模式之美
登录|注册

15 | 理论一:对于单一职责原则,如何判定某个类的职责是否够“单一”?

王争 2019-12-06
上几节课中,我们介绍了面向对象相关的知识。从今天起,我们开始学习一些经典的设计原则,其中包括,SOLID、KISS、YAGNI、DRY、LOD 等。
这些设计原则,从字面上理解,都不难。你一看就感觉懂了,一看就感觉掌握了,但真的用到项目中的时候,你会发现,“看懂”和“会用”是两回事,而“用好”更是难上加难。从我之前的工作经历来看,很多同事因为对这些原则理解得不够透彻,导致在使用的时候过于教条主义,拿原则当真理,生搬硬套,适得其反。
所以,在接下来的讲解中,我不仅会讲解这些原则的定义,还会解释这些原则设计的初衷,能解决哪些问题,有哪些应用场景等,让你知其然知其所以然。在学习的时候,希望你能跟上我的思路,把握住重点,真正做到活学活用。

如何理解单一职责原则(SRP)?

文章的开头我们提到了 SOLID 原则,实际上,SOLID 原则并非单纯的 1 个原则,而是由 5 个设计原则组成的,它们分别是:单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则,依次对应 SOLID 中的 S、O、L、I、D 这 5 个英文字母。我们今天要学习的是 SOLID 原则中的第一个原则:单一职责原则。
单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。这个原则的英文描述是这样的:A class or module should have a single reponsibility。如果我们把它翻译成中文,那就是:一个类或者模块只负责完成一个职责(或者功能)。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《设计模式之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(75)

  • 编程界的小学生
    1.方法就是全凭感觉。感觉不爽,就尝试着是否可以拆分多个类,感觉来了谁也挡不住。没有硬性要求吧,都是凭借经验。比如用户service可能包含用户的登录注册修改密码忘记密码等等,这些操作都需要验证邮箱,这时候你会发现这个类就很乱,就可以把他一分为二,弄个UserService再弄个UserEmailService专门处理用户相关邮件的操作逻辑,让UserService依赖Email的,等等这种,我觉得真的是全凭经验。换句话说,屎一样的代码写多了,写到自己看着都想吐的时候,经验就积累了。
    2.方法设计上也用到了,比如自上而下的编程方式,先把核心方法定义好在去写具体细节,不要上来就把所有的细节都写到一个大而全的方法里。自上而下的编程方式他不香吗?
    2019-12-06
    14
    26
  • blacknhole
    在看文末的“3. 类的职责是否设计得越单一越好?”时,我惊喜地意识到:

    1,内聚和耦合其实是对一个意思(即合在一块)从相反方向的两种阐述。

    2,内聚是从功能相关来谈,主张高内聚。把功能高度相关的内容不必要地分离开,就降低了内聚性,成了低内聚。

    3,耦合是从功能无关来谈,主张低耦合。把功能明显无关的内容随意地结合起来,就增加了耦合性,成了高耦合。
    2019-12-06
    2
    23
  • 辣么大
    懂几个设计模式,只是花拳绣腿。掌握设计原则就才掌握了“道”。

    设计你的系统,使得每个模块负责(响应)只满足一个业务功能需求。
    Design your systems such that each module is responsible (responds to) the needs of just that one business function. (Robert C. Martin)

    参考:https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html
    2019-12-06
    6
  • 下雨天
    回答问题
    1. 类单一职责判断可以通过评估其对外提供接口是否满足不断变化的业务和需求来确定!问自己,该类是否对其他类是"黑盒"!

    2. 类行数多=属性多+方法多
    属性多: 要考虑这些属性是不是对类来说是必须的,需要移除么?
    方法多: 方法间复用情况,方法间有没有写重复代码?
    如上如果觉得没有可以改进的余地,就可以认为类行数恰当!

    3. 单一职责还可以应用到方法,模块,功能点上!
    2019-12-06
    6
  • Luciano李鑫
    想请教一下争哥,关于代码代码持续重构的问题,所引出的额外测试、发布成本,和故障风险应该怎样平衡呢。

    作者回复: 我推荐持续重构,不推荐等到代码烂到一定程度之后的大刀阔斧的重构。持续重构就像开发一样,是开发的一部分,所以也不存在额外的测试、发布成本之说,你就当成开发来看就行了。后面会讲到重构,你到时候再看下是否还有疑问。

    2019-12-06
    4
    4
  • 墨雨
    我有个问题,就用户地址的设计来说,后续功能扩大再拆解是不是违反了开闭原则呢?而且后期拆分会比较影响现有业务逻辑吧,这个如何平衡呢?
    2019-12-06
    4
    4
  • Chen
    Android里面Activity过于臃肿会让感觉很头大,MVP,MVVM等框架都是为了让Activity变得职责单一。
    2019-12-06
    2
    4
  • Dimple
    因为学习设计模式,前几天刚和朋友在聊,说其实每个类的代码行数和函数的行数最好都需要控制下,能精简就精简,完成我们理解的重构。

    刚好,今天就看到老师说的这个,赶紧分享给朋友,盛赞了这门课,哈哈
    2019-12-06
    3
  • 啦啦啦
    单一职责原则也可以用在服务上的拆分上
    2019-12-06
    3
  • 黄林晴
    打卡✔
    安装ali规范插件,看到报警告的就按照规范修改,不过这个规范是死的,有时候和实际应用不同,不过大部分规范还是可以遵循的
    2019-12-06
    2
  • 赤城
    项目初始阶段也是雄心勃勃,要把系统做出一个快速迭代、维护性高的系统,可是不断的需求变更导致开发任务过重,留给项目整体的思考和重构时间被严重压缩,最终导致项目的技术管理失控,再加上人员变动等原因,项目死亡的概率急剧上升,都是惨痛的教训。

    《三体》中常伟思的父亲经常说的是:要多想。

    共勉!
    2019-12-09
    1
  • 李小四
    设计模式_15
    # 作业:
    单一职责也可以用于方法的编写,在维护多年的项目中,我们会看到一些非常“庞大”的方法,这些方法的功能比它的命名丰富很多,它是一次次地改成了这个样子。本来是一个职责单一的简单方法,由于需求的变化,可能是方法被调用太多(不敢改),也可能是框架设计(不能改)导致只能在方法内部添加特殊业务的判断条件,这样下来,这个方法就变得难以理解且难以维护。

    # 感想
    同事们也常讨论单一职责的边界, 始终没有一致的结论。今天的内容也坚定了观点,业务的发展一定程序决定了耦合的边界。
    我们学习前人总结的这些原则,目的是什么呢,我今天的感受是,系统性地降低工作量和出错概率。
    - 降低工作量:我们要尽量保证,随着需求的增加,工作量的增加是线性的,而不是指数级的。据我了解,维护一些老代码的同学们,一直被产品同事质疑:就这么点功能,要做这么久吗???
    - 降低出错概率:就像文中的序列化的例子,强行把序列化与反序列化方法拆开,会导致使用者需要花更多的时间来做一些同步的工作,如果文档不够清晰,或者阅读文档不够仔细,就会导致出错;有这样代码结构的系统,运行足够长的时间,一定会出更多的错误。
    2019-12-07
    1
  • 相逢是缘
    打卡
    1、单一职责原则定义:一个类或是模块只完成一个职责(或功能)
    2、如何做到单一职责,有几个方法可以参考
    1)类中的代码行数和属性太多;
    2)类依赖的其他类过多;
    3)类的私有方法过多,考虑是否可能把一些公用的方法放到其他的类中,作为公有方法,提供代码复用性;
    4)比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的 Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;
    5)类中大量的方法都是集中操作某几个属性,可以考虑把这几个属性和方法抽取出来;

    3、在不同的应用场景和不同的需求背景下,类的单一职责判断是不同。随着需求的变动,功能的增加,原来的类可能就不满足单一职责原则,就需要拆分为颗粒度更小的类;

    4、类的颗粒度拆分也需要适度,把负责单个功能的类拆分为多个类,反而破坏了高内聚的原则(虽然满足了低耦合)。

    5、在需求实现初期,可以写个颗粒度大的类,满足业务需求。当某个类的代码越来越多,负责的职责越来越多,可以查分为更小颗粒度的类。(持续重构的思想)
    2019-12-07
    1
  • ww yang
    每次学完都很期待下一节课马上来!
    2019-12-06
    1
  • 潇潇雨歇
    1、如何判断代码行数过多,这个我还是觉得要看感觉,如果自己看着觉得很不爽,那说明应该要拆分或者优化精简了;如果自己看不太出来可以找人review,别人或许能看出来。不过代码行数最好不要太多。
    3、方法设计,接口设计等等,都可以使用单一职责,每个方法做一件事,如果里面的代码多了或者乱了,就应该试着拆分,接口设计也是同理,做某一个模块的事情,不能多个模块都写在一个接口里面。
    2019-12-06
    1
  • whistleman
    根据不同的场景对某个类或模块单一职责的判断是不同的,不能为了拆分而拆分,造成过度设计,难以维护。
    2019-12-06
    1
  • 单一职责,感觉不应该用代码行数来判定,确实应该由业务需求场景决定,有些业务场景不复杂,过分强调单一,反而会使代码片段零散在过多的类、方法中,导致调用层级过深,不易阅读和理解,难以维护,万事都有个平衡,适度就好,毕竟代码不是一次成型的建筑物,需要持续的改造、优化。

    单一职责感觉是最基础也是起他设计模式用好的前提,考量单一的时候还有一个原则就是:复用性,如果一块逻辑或业务可以被起他地方利用,也是标志整块逻辑的职责是单一性的。单一职责没有一个确切的标准,很多场景下在一个业务中对于权衡单一指责的考虑纬度、粒度也所有不同。虽然是很简单易懂的指责,但用好确实并不是很容易的事。
    2019-12-06
    1
  • 业余草
    单一职责(一个萝卜一个坑)、里氏替换(继承复用)、依赖倒置(面向接口编程)、接口隔离(高内聚、低耦合)、迪米特法则(降低类与类之间的耦合)、开闭原则(对扩展开发、对修改关闭)。
    2019-12-14
  • Geek_e9b8c4

    DS:曾经做过有个物流项目,比如有两个方法,1、查询司机订单;2、查询企业订单,这两个方法是都放OrderService 呢,还是分别放在DriverService和CompanyService类里? 简单的判断就是根据返回的类型来决定。返回订单类型的方法就放在OrderService。现实项目中遇到过很多类似的功能方法,不知道到哪去找!
    2019-12-13
  • Geek_e9b8c4
    DS:一处修改引起了多处功能性质类似的类的变动 ,或者多个类中的代码有重复,一个思考方向:考虑合并为同一个类
    2019-12-13
收起评论
75
返回
顶部