作为一个程序员,不懂程序设计是不会有未来的。那些需要重构的代码通常是因为编码时缺乏相应的程序设计。
单一职责原则,又称单一功能原则,出自《敏捷软件开发:原则、模式和实践》
通俗的说法是一个类,最好只负责一件事
。更准确点说是只有一个引起它变化的原因
。
所谓职责
是指类变化的原因。如果一个类有多于一个的动机
被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因
。
问题来源
T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说职责P1和P2被耦合在了一起。
结合实际业务来说,比如我们有个故事
是在除夕夜给充值满1000元的用户发送一条过年祝福短信
。当我们去实现这个故事
的时候,发现要对发送短信
的功能进行修改才可以实现,改完之后发现之前的一个故事用户充值成功后发送一条充值成功的短信
不好用了。
产生原因
任何程序设计人员都很清楚高内聚低耦合
,很多耦合都发生在不经意间,通常我们把此类耦合归类为职责扩散
。
解决方法
遵守单一职责原则,将不同的职责封装到不同的类或模块中。
引申
看起来很简单的一个原则,但是实际设计上却很难。
从更高的层次去看,到开发人员这一层级的程序设计大多基于需求
,也就是我们平时说的基于需求分析做好程序设计
。
而从事软件开发很多年的资深开发人员,都会有自己的一套经验,不知不觉的向单一职责原则
去靠拢,因为单一职责原则
带来的一些便利很可能让他在实际工作中受益。
实践中的不成体统的经验
当前前后分离
的环境下,后端服务提供API即可。我们从简单的一个故事
开始做分析,比如API返回某个人的基于大数据分析的用户信息
。
No.1
这时候如果不做设计,直接进行开发,可能就会出现如下的情况,我们编写了一个DTO,直接将用户信息返回。
public class UserDto {
private String userId;
private String userName;
private String userIcon;
private String userTag;
...
}
复制代码
单从API的维度来说,其实是符合职责单一原则
的。
但是显而易见,这个UserDto
得属性很多,这时候如果有关于用户的数据分析数据增多时,都会导致该DTO的变动。
No.2
我们不希望我们的DTO做经常的变动,即使变动,也希望能控制住其影响范围。这时候,我们就需要对这些用户的属性进行分类,当然可以借助于某些分类工具,比如亲和图
。
通过分类来划分DTO是一种简单直接的方式,这时候随着数据分析
的数据增加,只需要扩充对应的DTO即可。同样,我们的通过浏览分析出的属性
、通过操作分析出的属性
、通过购物分析出的属性
等等功能都是单一的,如果发生变更,那么涉及到的职责很少。
No.3
以上是一种自上而下
的方式,通过API的定义来细分功能,也是一种简单而快速的设计方式,比较适合快速迭代。
同样,我们也可以自下而上
的去拆解。
- 功能1: 通过浏览分析出的用户属性
- 功能2: 通过操作分析出的用户属性
- 功能3: 通过购物分析出的用户属性
- ……
通过拆解功能来进行解耦合。
其他方法
- 模块化编程
- 严格的代码审核杜绝职责扩散
- 拥抱变化的程序设计方法
总结
非严格意义上说,每当需求变化来临时,改动的类越少,证明之前越符合低耦合
的设计,同时影响的范围也越小。
符合原则的设计通常会减少工作量(现在&未来)。