嘻哈说:设计模式之单一职责原则
1、定义
首先呢,我们来看一下单一职责原则的定义。
就一个类而言,应该只有一个引起它变化的原因
这个说法不是很好懂,有一些抽象,不过呢,我们依旧可以尝试着理解一下。
就一个类而言,只有一个引起它变化的原因,也就是说,除此之外,不能有其它引起变化的原因。
这样就需要一个前提,这个类只能负责一项职责,而不能负责其他的职责,不然,其他的职责就会存在其他变化的原因了。
通俗的说,即一个类只负责一项职责。
懒人就比较喜欢这种通俗地定义,一目了然。
懒人曾经总结过:通俗的定义,浅显易懂;理论的定义,大脑一懵。
有同感的小伙伴请双击666。
2、场景
餐馆聚餐,通过服务员点餐
这是一个比较常见的场景,比如懒人撸了五天的代码,身心疲惫,周末的时候呢,就约上三五个好友,去餐馆(番茄餐厅)happy一下(非常单纯的吃饭)。我们刚刚坐下,就来了一位很漂亮的服务员为我们点餐。
这样一个服务员为我们点餐的场景,一般都是什么样的流程?
第一步:客人点餐
懒人:咱呢,不但要吃饱,还要吃好!服务员,先来一份西红柿炒鸡蛋,再来一份酸辣土豆丝!!!
好友:脸呢。。。说好的脸呢。。。
服务员:你是顾客,你是上帝,你说啥就是啥,不过,你刚才说的是啥。。。
第二步:烹饪美食
西红柿炒鸡蛋,先炒鸡蛋,再炒西红柿。。。ok,出锅。
第三步:上餐
服务员:这是您点的西红柿炒鸡蛋,请您慢用。
3、实现
不废话,撸代码。
package com.fanqiekt.principle.single;/**
* 服务员
* @Author: 番茄课堂-懒人
*/
public class Waiter {/*** 下单* @param dishName 菜名*/public void order(String dishName){System.out.println("客人点餐:" + dishName);System.out.println("开始烹饪:" + dishName);//菜品不同,做法不同。switch (dishName){case "西红柿炒鸡蛋":System.out.println("先炒鸡蛋");System.out.println("再炒西红柿");System.out.println("...");break;case "酸辣土豆丝":System.out.println("先放葱姜蒜");System.out.println("再放土豆丝");System.out.println("...");break;}System.out.println(dishName + "出锅");System.out.println(dishName + "上桌啦,请您品尝");}
}
服务员这个类比较简单,就一个下单的方法。
为了更好的理解,懒人进行了细节的优化(主要是很多细节懒人压根不了解)。
package com.fanqiekt.principle.single;/*** 客户端* @Author: 番茄课堂-懒人*/
public class Client {public static void main(String[] args){Waiter waiter = new Waiter();waiter.order("西红柿炒鸡蛋");System.out.println("-------");waiter.order("酸辣土豆丝");}
}
客户端这个类就相当于客人,客人负责通过服务员点餐。
客人一共点了两道大餐,西红柿炒鸡蛋、酸辣土豆丝,我们来运行一下,看看结果。
客人点餐:西红柿炒鸡蛋
开始烹饪:西红柿炒鸡蛋
先炒鸡蛋
再炒西红柿
...
西红柿炒鸡蛋出锅
西红柿炒鸡蛋上桌啦,请您品尝
-------
客人点餐:酸辣土豆丝
开始烹饪:酸辣土豆丝
先放葱姜蒜
再放土豆丝
...
酸辣土豆丝出锅
酸辣土豆丝上桌啦,请您品尝
OK,两个热气腾腾的饭菜就做好了。
我们回过头来看一下waiter类,大家觉得这个类好不好?
肯定是不好了,那…不好在哪里?
这就好比一个小作坊,老板既负责点餐又负责下单,就跟waiter类一样。
我们一般在小作坊吃饭,感受会怎么样?
乱,非同一般的杂乱。上菜需要等半天,点餐的时候找不到人。
还有一个弊端,我修改了做饭的流程,会影响下单的业务,增加修改的风险,为什么这么说呢?
客人A:老板,给我来一份酸辣土豆丝。
老板:好嘞,您稍等。
懒人:老板,我刚才点的西红柿鸡蛋要少放盐啊。
老板:好的,我放盐的时候用小点的勺子。
客人A:老板,我的菜做了吗?我的同伴都吃完了,没做我就不要了!
老板:您的菜已经做了,马上就要出锅了。(内心:我勒个去,刚才用小勺放盐的时候把这哥们点的单给忘了,这就尴尬了。。。)
不难看出,当功能冗杂到一个对象中,这样修改就会增加风险。那我们该如何避免呢?
一般比较完善的餐馆,还至少会有一名厨师。
厨师做饭,服务员点餐,这样做,有什么好处呢?
一来,结构清晰了,各司其职,一目了然。二来,风险降低了,我修改做饭的流程,不会影响下单的业务。
只负责一项职责,这就是单一职责原则。
那我们尝试着增加一个厨师类。
package com.fanqiekt.principle.single;/*** 厨师** @author 番茄课堂-懒人*/
public class Chef {/*** 做饭* @param dishName 下单的菜名*/public void cooking(String dishName) {System.out.println("开始烹饪:"+dishName);switch (dishName){case "西红柿炒鸡蛋":System.out.println("先炒鸡蛋");System.out.println("再炒西红柿");System.out.println("...");break;case "酸辣土豆丝":System.out.println("先放葱姜蒜");System.out.println("再放土豆丝");System.out.println("...");break;}System.out.println(dishName + "出锅");}
}
厨师类,只负责了一项职责:做饭。
这就是类的单一职责原则。
Chef类只有一个cooking方法,cooking方法是根据下单的菜品名称去烹饪不同的菜,以及炒西红柿鸡蛋以及酸辣土豆丝的具体烹饪过程。这样做合适吗?
不合适的,cooking方法应该只有菜品分发这一项职责,而炒西红柿鸡蛋以及酸辣土豆丝这两件事显然易见与分发没有任何关系,所以拆分出来效果会更好。
我们将厨师类再优化下。
package com.fanqiekt.principle.single;/*** 厨师** @author 番茄课堂-懒人*/
public class Chef {/*** 做饭* 方法的单一职责原则* @param dishName 下单的菜名*/public void cooking(String dishName) {System.out.println("开始烹饪:"+dishName);switch (dishName){case "西红柿炒鸡蛋":cookingTomato();break;case "酸辣土豆丝":cookingPotato();break;}System.out.println(dishName + "出锅");}/*** 炒西红柿鸡蛋*/private void cookingTomato() {System.out.println("先炒鸡蛋");System.out.println("再炒西红柿");System.out.println("...");}/*** 炒酸辣土豆丝*/private void cookingPotato() {System.out.println("先放葱姜蒜");System.out.println("再放土豆丝");System.out.println("...");}
}
优化后Chef类有三个方法。
cooking方法是根据下单的菜品名称去烹饪不同的菜。
cookingTomato方法是炒西红柿鸡蛋。
cookingPotato方法是炒酸辣土豆丝。
每个方法只负责一项职责,这就是方法的单一职责原则。
遵守方法单一职责原则的类,是不是更加的直观?修改各自的方法是不是也没有影响到其他的方法?
接下来,我们再优化下Waiter类,让他遵循类的单一职责原则。
package com.fanqiekt.principle.single;/*** 单一职责原则的服务员** @author 番茄课堂-懒人*/
public class Waiter {private Chef chef = new Chef();/*** 点餐* @param dishName 餐名*/public void order(String dishName) {System.out.println("客人点餐:"+dishName);chef.cooking(dishName);System.out.println(dishName+"上桌啦,请您品尝!");}
}
优化后SingleWaiter类有只负责点餐、上餐这些与服务员相关的职责,而做饭的这些无关的职责则交给了Chef。
遵守类单一职责原则的项目,是不是更加的直观?修改各自的类是不是也没有影响到其他的类?
接下来,我们把Client运行一下。
客人点餐:西红柿炒鸡蛋
开始烹饪:西红柿炒鸡蛋
先炒鸡蛋
再炒西红柿
...
西红柿炒鸡蛋出锅
西红柿炒鸡蛋上桌啦,请您品尝
-------
客人点餐:酸辣土豆丝
开始烹饪:酸辣土豆丝
先放葱姜蒜
再放土豆丝
...
酸辣土豆丝出锅
酸辣土豆丝上桌啦,请您品尝
结果与原来一致。
4、优点
撸过代码后,我们发现单一职责原则的几个优点。
提高类的可读性
符合单一职责原则的方法、类,结构会更加的清晰,类的可读性也就提高了。
降低类的复杂性
一个类只负责一项职责,一个方法也只负责一项职责。肯定要比功能冗杂到一个方法,一个类中要简单得多。
降低风险
修改其中的一个业务,不会影响到业务。
5、总结
我们必须要意识到,一味的遵守单一职责原则,不停的分拆类所付出的开销是很大的。
这时候就涉及到平衡的问题,平衡单一职责原则与修改造成的开销。
懒人的观点是如果一个方法逻辑不复杂的情况下,可以修改方法实现,否则要拆分为两个方法,遵循方法级别的单一职责原则。
如果一个类方法不多的情况下,可以只增加方法,而不用分拆为多个类,否则要拆分为多个类,遵循类级别的单一职责原则。
6、嘻哈说
接下来,请您欣赏单一职责原则的原创歌曲。
嘻哈说:单一职责原则
作曲:懒人
作词:懒人
Rapper:懒人周末约上了好友去熟悉的餐馆聚餐
只负责点餐的漂亮服务员保持笑容已经成为习惯
只负责做饭的帅气厨师一直待在了烟雾弥漫了几遍的厨房里面
每个人有自己负责的地盘
就像单一职责
一个类只有一个职责 好体面
它降低了类的复杂性
它提高了类的可读性
那风险被降低代表着单一职责没毛病
试听请点击这里
闲来无事听听曲,知识已填脑中去;
学习复习新方式,头戴耳机不小觑。
番茄课堂,学习也要酷。
更多精彩课程,请关注番茄课堂公众号。
嘻哈说:设计模式之单一职责原则相关推荐
- 北风设计模式课程---单一职责原则
北风设计模式课程---单一职责原则 一.总结 一句话总结: 视频教程网上一定能找到做好笔记的博客,很大几率都不需要自己做笔记.比如北风设计模式课程,https://www.cnblogs.com/xi ...
- 前端中会用到的设计模式之单一职责原则
1:设计模式应用不应用,取决于对现在和未来判断后的取舍.没必要用尽量不用! 2.设计模式的目的是 减少复杂度(一个函数中包含的功能个数), 降低耦合度(一个对象与其他对象的关系个数).耦合度不能为0 ...
- 设计模式:单一职责原则
1.单一职责原则的概念 Single Responsibility Principle,SRP: 一个类被改变的原因不能超过一个,也就是说,一个类只有一个职责,如果职责过多,代码就会臃肿,可读性更差, ...
- 设计模式之单一职责原则
超前的设计或者过度的设计都不是良好的设计,很多时候我们等到代码在第一次变化的时候可以及时作出反应. What 就一个类(接口.结构体.方法等等)而言,应该仅有一个引起它变化的原因. Why 软件设计真 ...
- 围观设计模式(1)--单一职责原则(SRP,Single Responsibility Principle)
沉寂了一个月的时间,仔细学习了下设计模式,从本篇博文开始陆续更新设计模式系列的文章,我给它起了个有意思的名字叫做:"围观"设计模式,当然围观是加引号的,我写博文分享的目的一方面是将 ...
- 【设计模式】单一职责原则
单一职责原则 原则概述:一个类或者一个方法只负责一项职责或功能.如[类A]负责两个不同职责,即[职责1]和[职责2].当[职责1]需求变更而改变[类A]时,可能引用[类A对象]的[职责2]时执行错误, ...
- java 单一职责原则_设计模式之单一职责原则
对类来说,即一个类应用只负责一项职责,如类A负责两个不同的职责:职责1,职责2.当职责1需求变更时,可造成职责2执行错误,所以需要将类A的粒度分解为A1,A2. 降低类的复杂度,一个类只负责一项职责 ...
- 1. 目标精通--用java写设计模式:单一职责原则
文章目录 1.什么是单一职责原则 2. 单一职责原则的认识 3. 代码案例 3.1 一个正常的代码 3.1.1执行结果 3.1.2 分析 3.2 职责扩散 3.2.1 执行结果 3.2.2 分析 3. ...
- 设计模式(单一职责原则)
一 . 单一职责原则(Single Responsibility Principle, SRP) 1. 一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原 ...
最新文章
- R语言dplyr包coalesce函数处理缺失值(missing value)实战
- call/apply/bind 的理解与实例分享
- 数据备份_「Cassandra实战」Cassandra数据备份
- dev-sidecar安装桌面版
- 安卓ssr无网络连接_解决Android模拟器网络问题(使用了代理的情况下)
- 什么是OR MAPPING
- FPGA不可综合语句
- iOS开发之字符串(NSString)的拼接
- oracle 删除数据_Oracle海量数据表标准删除方案--分步分阶段大表删除
- .NET后台输出js脚本的方法
- VS2015正确卸载方法,亲测
- 怎么在win7上安装AIR780E的USB驱动
- 分享一个可以让你在朋友圈赚钱的小工具
- java用zipOutputStream压缩后用WinRAR解压出现“不可预料的压缩文件末端”错误
- 多种好看好玩的词云例子Example
- 大数据线性回归预测学生成绩
- 配置文件工具类【ConfigTools】
- 神经网络处理表格数据,神经网络如何识别图像
- 网页打开android app,网页打开Android APP
- 「聚变」前端 客户端 | 第十七届 D2 终端技术大会,开放报名!
热门文章
- android – 多屏幕适配相关
- 点到超平面的距离公式
- DB 查询分析器 6.04 发布 ,本人为之撰写的相关技术文章达78篇
- 简单的 JSONParser
- FreeMarker数值数据处理问题
- 相干光和非相干光的区别
- 每天五分钟机器学习:随着算法迭代次数动态调整学习率
- 串行通信协议(I2C、SPI、UART、SCCB、CAN)
- 主题模型结合词向量模型(Improving Topic Models with Latent Feature Word Representations)
- java 单链表一元多项式_java单链表实现一元多项式加法和乘法运算