设计原则:单一职责(SRP)原则
1 什么是单一职责(SRP)原则
单一职责原则的英文是 Single Responsibility Principle,缩写为 SRP。翻译过来就是:一个类或者模块只负责完成一个职责(或者功能)。
所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。
很多人认为这个原则是针对一个类进行描述,在我看来这里使用模块这个更加抽象的名词更为合适。在设计中,小到一个方法,大到一个模块我们都应该尽量取遵循单一职责原则。
2 为什么要遵循单一职责
相信在我们日常开发中,每个人都遇到过改了一个问题经常会引起另一个问题。其原因大多都是因为在设计上违背了单一职责原则。
如果一个类承担的职责过多,就等于把这些职责耦合在一起了。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。而如果想要避免这种现象的发生,就要尽可能的遵守单一职责原则。此原则的核心就是解耦和增强内聚性,是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。。
如下图,就是一个非常明显的不满足单一职责的类。我们的业务类UserService中包含了add、log、persistence三个方法,同时也包含了三个职责业务添加、日志记录、持久化。而实际上我们的业务规则可能是经常变化的,但是我们的持久化方法和日志记录是不常变化的。由于耦合在一个类中我们频繁改动的业务方法,很有可能影响到日志记录与持久化。又或者是我们日志记录和持久化方法这与业务无关的变动也很有可能影响到我们的正常的也业务逻辑。
正确的做法是将他们分离开来。

3 如何判断职责是否足够单一
对于单一职责这一原则的定义和描述,相信每一个程序员都能张口就来。它理解起来也并不难,即我们不要设计大而全的类或模块,要尽量设计粒度小、功能单一的模块。但实际应用过程中确是非常困难的,也是一个非常有争议性的原则,原因就在于如何去判断职责是否足够单一。就像做菜一样,“放盐少许”,那么这个少许到底是多少?你与专业大厨的区别就在于对这个度的把握。
程序设计也是如此,上面那个例子是非常简单的一眼就能区分职责。但实际开发中往往有很多场景会让你对职责是否单一的判定难以拿捏。
如下面这个用户类是否满足单一职责呢?

我们可以看到,省市区地址信息在用户信息类里面,这种情况下你说它满足不满足似乎都有道理。这时就要根据具体的业务场景来看,如果你的业务场景中地址信息仅仅作为用户信息的一部分展示来看,这么设计就是合理的。而如果你的地址信息有一些单独的逻辑,那么就是不符合单一职责的。比如电商系统。
此时我们就要把地址信息拆分出来

再如社交系统中,也许起初地址信息只是用于用户信息的一部分来展示,但是随着业务的发展多了一些根据地址信息推荐好友等特殊的需求。那么我们就要在业务演进的过程中把类进行拆分。
综上所述,我们可以总结出
- 不同的应用场景,对同一个类的职责是否单一的判定,是不一样的。我们需要具体场景具体分析
- 一个类的设计可能已经满足单一职责原则了,但可能随着需求的迭代在未来的某个时候就不再满足单一职责原则了,此时我们没必要过于未雨绸缪,过度设计。可以先满足业务需求。随着业务的发展,如果类变得越来越庞大,代码越来越多,不再满足单一职责,这个时候,再把这个类持续进行重构拆分。
4 职责设计是否越单一越好
我们再来思考一个问题,为了满足单一职责原则,是不是把类拆得越细就越好呢?
比如我们常用与接口通信的类与序列化操作类

这时如果我们进一步把Get、 Post, Serialize,Derialize进行拆分到两个类里面,看似更好的遵循了单一职责原则,但实际上如果我们的协议格式发生改变或者序列化方式发生改变,那么就要去更改两个类的代码,如果我们漏掉了一个,后果可想而知。
5 不满足单一职责的坏味道
随着开发经验的积累,我们是很容易嗅到一些不满足单一职责的坏味道的
- 类的代码行数过多
- 类依赖的其他类过多
- 过长的方法
- 私有方法过多
- 不容易给类起名字,类名中包含两个或以上的名词
小结
单一职责原则是开发中最基础,最简单,确是最难把握的一个原则,我们需要不断地学习以及大量经验的积累,才能更好的掌握它。此外没有最好的设计,只有合适的设计,我们需要结合真实的业务场景。记住:无论任何的思想与原则的最终目的是让我们的代码具有更好的可读性、可维护性、可扩展性......
系列文章
关注下方公众号,回复“代码的艺术”,可免费获取重构、设计模式、代码整洁之道等提升代码质量等相关学习资料
设计原则:单一职责(SRP)原则的更多相关文章
- 编写具有单一职责(SRP)的类
这两周我需要对一个历史遗留的功能做一些扩展,正如很多人不愿意碰这些历史遗留的代码一样,我的内心也同样对这样的任务充满反抗.这些代码中充斥着各种null判断(你写的return null正确吗?),不规 ...
- 六大设计原则——单一职责原则【Single Responsibility Principle】
声明:本文内容是从网络书籍整理而来,并非原创. 用户管理的例子 先看一张用户管理的类图: 再看一眼上面的图,思考:这样合理吗? 这个接口是一个很糟糕的设计! 用户的属性和行为竟然混合在一起!!! 正 ...
- S.O.L.I.D五大原则之单一职责SRP
转自 : 汤姆大叔的blog Bob大叔提出并发扬了S.O.L.I.D五大原则,用来更好地进行面向对象编程,五大原则分别是: The Single Responsibility Principle(单 ...
- 深入理解JavaScript系列(6):S.O.L.I.D五大原则之单一职责SRP
前言 Bob大叔提出并发扬了S.O.L.I.D五大原则,用来更好地进行面向对象编程,五大原则分别是: The Single Responsibility Principle(单一职责SRP) The ...
- 面向对象设计原则 单一职责原则(Single responsibility principle)
单一职责原则(SRP:Single responsibility principle) 又称单一功能原则,面向对象的基本原则之一.它规定 一个类应该只有一个发生变化的原因. 该原则由罗伯特·C·马丁( ...
- 设计模式值六大原则——设计模式之六大原则——单一职责原则(SRP)
定义: 应该有且仅有一个原因引起类的变更. There should never be more than one reason for a class to change. 优点: 1.类的复杂性降 ...
- Java设计原则—单一职责原则(转)
定义: 应该有且仅有一个原因引起类的变更. There should never be more than one reason for a class to change. 优点: 1.类的复杂性降 ...
- 【设计原则和编程技巧】单一职责原则 (Single Responsibility Principle, SRP)
单一职责原则 (Single Responsibility Principle, SRP) 单一职责原则在设计模式中常被定义为“一个类应该只有一个发生变化的原因”,若我们有两个动机去改写一个方法,那这 ...
- 面向对象设计原则一:单一职责原则(SRP)
单一职责原则(SRP) 定义:系统中的每一个类都应该只有一个职责. 好处:高内聚.低耦合. 解释说明: 单一职责也就是说我们应该让一个类或一个对象只做一件事情,每个类所要关注的就是自己要完成的职责是什 ...
随机推荐
- Dart 处理json,built_value库
原文链接 文档 import 'dart:convert'; main() async { // json 转化为 map String jsonStr = ''' [ {"name&quo ...
- Renice INC:法国葡萄酒为什么独占世界鳌头?
提起葡萄酒,许多人首先想到的就是法国.法国有着悠久的酿酒历史和精湛工艺,"82年的拉菲"几乎成了大众认识葡萄酒的代名词.市面上的进口葡萄酒琳琅满目,原产国众多,意大利.西班牙.美国 ...
- LoveWord
个人喜欢的句子汇总! 我告诉你我喜欢你,并不是一定要和你在一起,只是希望今后的你,在遭遇人生低谷的时候,不要灰心,至少曾经有人被你的魅力所吸引,曾经是,以后也会是----村上村树
- CentOS7安装Kibana7.9.2
1:下载 wget https://artifacts.elastic.co/downloads/kibana/kibana-7.9.2-linux-x86_64.tar.gz 点击进入官网 安装手册 ...
- React Context 理解和使用
写在前面 鉴于笔者学习此内容章节 React官方文档 时感到阅读理解抽象困难,所以决定根据文档理解写一篇自己对Context的理解,文章附带示例,以为更易于理解学习.更多内容请参考 React官方 ...
- TorchVision 预训练模型进行推断
torchvision.models 里包含了许多模型,用于解决不同的视觉任务:图像分类.语义分割.物体检测.实例分割.人体关键点检测和视频分类. 本文将介绍 torchvision 中模型的入门使用 ...
- su: Authentication failure解决方法
su命令不能切换root,提示su: Authentication failure,需要sudo passwd root一次之后,下次再su的时候只要输入密码就可以成功登录.
- pyhton的函数
目录 一.函数引入 二.函数的定义 三.如何定义一个函数 四.定义函数的三种形式 1.空函数 2.有参函数 3.无参函数 五.函数的调用 六.函数的返回值 七.函数的参数 1.形参 1.1 位置形参 ...
- [CentOS7]Windows下VirtualBox虚拟机磁盘扩容
目录 虚拟系统磁盘文件扩充 修改分区 LVM更新 扩容文件系统 参考资料 虚拟系统磁盘文件扩充 命令操作 命令行运行VBoxManage,modifyhd扩容需要文件格式为.vdi,如为.vmdk,需 ...
- MySQL注入与informantion_schema库
目录 只可读 自动开启 和MySQL注入有关的3个表 手动注入的使用案例 表介绍 查询一个表中全部字段的过程 MySQL V5.0安装完成会默认会生成一个库(informantion_schema), ...