设计原则:单一职责(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) 定义:系统中的每一个类都应该只有一个职责. 好处:高内聚.低耦合. 解释说明: 单一职责也就是说我们应该让一个类或一个对象只做一件事情,每个类所要关注的就是自己要完成的职责是什 ...
随机推荐
- SPEC-RFC3261总述
最近学习VoLTE(Voice Vver LTE)相关知识,而学习VoLTE必须要学相关的协议,最基础的就是RFC3261,RFC3261的全称是:SIP: Session Initiation Pr ...
- 02.描述统计 (descriptive statistics)
1.数据的可靠性和有效性 2.利用图表对数据进行可视化 2.1分类变量的可视化 2.11无序分类变量 2.12有序分类变量的可视化 2.1数值变量的可视化 数据的分布
- mybites框架遇到的坑之Mapper.xml文件不要随意加注释和ORA-00911
原文链接:https://blog.csdn.net/streetlight8023/article/details/69388495/ 先说解决方法: org.mybatis.spring.MyBa ...
- 学习一下 SpringCloud (五)-- 配置中心 Config、消息总线 Bus、链路追踪 Sleuth、配置中心 Nacos
(1) 相关博文地址: 学习一下 SpringCloud (一)-- 从单体架构到微服务架构.代码拆分(maven 聚合): https://www.cnblogs.com/l-y-h/p/14105 ...
- Docker 镜像加速教程
原文链接:https://fuckcloudnative.io/posts/docker-registry-proxy/ 在使用 Docker 和 Kubernetes 时,我们经常需要访问 gcr. ...
- Java基础语法:JavaDoc
一.简介 JavaDoc是一种将注释生成HTML文档的技术,它从程序源代码中抽取类.方法.成员等注释形成一个和源代码配套的API帮助文档. 也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写 ...
- 数据结构-PHP 线段树的实现
转: 数据结构-PHP 线段树的实现 1.线段树介绍 线段树是基于区间的统计查询,线段树是一种 二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点.使用线段树可以快速的查 ...
- C++类的静态成员笔记
下面是C++类的静态成员笔记. 静态数据成员特征 用关键字static声明 为该类的所有对象共享,静态数据成员具有静态生存期 必须在类外定义和初始化,用(::)来指明所属的类 举例说明-具有静态数据成 ...
- CCF(URL映射:80分):字符串处理+模拟
URL映射 CCF201803-3 #include<iostream> #include<cstdio> #include<cstring> #include&l ...
- PicGo+Typora+Gitee设置图床
PicGo图床 使用 Typora 编辑 MarkDown 非常方便,但是图片插入后只能保存在本地,十分讨厌 所以,可以使用图床技术,将图片先保存到网络端,再应用到 Typora 中 PicGo应用获 ...