设计原则:单一职责(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) 定义:系统中的每一个类都应该只有一个职责. 好处:高内聚.低耦合. 解释说明: 单一职责也就是说我们应该让一个类或一个对象只做一件事情,每个类所要关注的就是自己要完成的职责是什 ...
随机推荐
- vuex bug & vue computed setter
vuex bug & vue computed setter https://vuejs.org/v2/guide/computed.html#Computed-Setter [Vue war ...
- moment.js 时间格式转换
moment.js 时间格式转换 moment.js 时间转化 bug 格式错误 bug 02:00 => 14:00 format HH 与 hh HH === 24 小时制 hh === 1 ...
- 用注解开发SpringMVC
Spring2.5以后,用注解开发SpringMVC的功能十分强大,注解也是SpringMVC的精髓.在实际开发中,都会使用注解来实现. 这让SpringMVC开发工作量最小化,开发者只要专注于业务逻 ...
- 学习js、jquery、vue实现部分组件
通过js实现radio小组件,最终效果如下 html代码: <!DOCTYPE html> <html lang="en"> <head> &l ...
- centos 修改系统时间
centos 修改系统时间 [echo0282@instance-1 ~]$ sudo timedatectl set-timezone Asia/Shanghai timedatefctl li ...
- CNN结构演变总结(一)经典模型
导言: 自2012年AlexNet在ImageNet比赛上获得冠军,卷积神经网络逐渐取代传统算法成为了处理计算机视觉任务的核心. 在这几年,研究人员从提升特征提取能力,改进回传梯度更新效果 ...
- MySql-Day-01
MySql 能够理解数据库的概念 能够安装MySQL数据库 能够启动,关闭及登录MySQL 能够使用SQL语句操作数据库 能够使用SQL语句操作表结构 能够使用SQL语句进行数据的添加修改和删除的操作 ...
- 440. 字典序的第K小数字 + 字典树 + 前缀 + 字典序
440. 字典序的第K小数字 LeetCode_440 题目描述 方法一:暴力法(必超时) package com.walegarrett.interview; /** * @Author WaleG ...
- Web微信协议
[文档]Web微信协议 1.登录 1.1 获取uuid(get) 请求 https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&red ...
- 如何在 C# 中使用 const,readonly,static
平时在开发时经常会用到 const,readonly,static 关键字,可以肯定这些关键词是完全不同的概念,但有时候他们在用法上很相似以至于在场景中不知道选择哪一个,这篇文章我们就来讨论 C# 中 ...