单一职责原则
单一职责原则
单一职责原则(Single Responsibility Principle
,SRP
)。
英文描述:
1 | A class or module should have a single responsibility |
中文翻译:
1 | 一个类或者模块只负责一个职责(或者功能) |
一、如何理解单一职责原则(SRP)?
单一职责原则的含义:
- 一个类只负责完成一个职责或者功能
- 不要设计大而全的类,而是设计粒度小、功能单一的类
比如,一个类里既包含订单的一些操作,又包含用户的一些操作。
订单和用户是两个独立的业务领域,将它们的功能都放在同一个类中,那就违反了单一职责原则。
需要将这个类拆分成两个粒度更细、功能更加单一的两个类:订单类和用户类。
二、为什么要用单一职责原则?
- 实现代码高内聚、低耦合
- 提高代码的复用性、可读性、可维护性
三、如何判定类的职责是否足够单一?
大部分情况下,类里的方法是否归为同一类,并不是那么容易判定的。
1 | public class UserInfo { |
UserInfo 类的设计是否满足单一职责原则呢?
对于这个问题,有两种不同的观点:
- UserInfo 类中都是跟用户相关的信息,都隶属于用户这样一个业务模型,满足单一职责原则
- 地址信息所占的比重较高,可以拆分成独立的 UserAddress 类,拆分后的两个类的职责更单一
这 2 种观点都可以说是正确的。
类的职责是否足够单一,实际上并没有一个明确的、可量化的标准:
- 不同应用场景下,对同一个类的职责是否单一的判定,可能都是不一样的
在某种应用场景下,一个类的设计可能已经满足单一职责原则了,但如果换个应用场景,可能就不满足了。
可以用一些侧面指标,来判定类的设计是否满足单一职责原则:
- 类中的代码行数、函数或者属性过多,多到不知道用哪个的时候
- 类依赖的其他类过多,或者依赖类的其他类过多
- 私有方法过多,就要考虑能否将私有方法独立到新的类中
- 比较难给类起一个合适的名字,或者只能用一些笼统的 Manager、Context 之类的词语来命名
- 经常集中操作类中的某几个属性,可以考虑将这几个属性单独抽出来做成一个类
满足这些情况之一,就说明类设计不符合单一职责原则,需要拆分。
但是也不必过于未雨绸缪,刚开始时不必过度设计:
- 可以先写一个粗粒度的类,暂时满足业务需求
- 随着业务的发展,代码越来越多,再考虑拆分成几个更细粒度的类
这种方式就是所谓的持续重构。
四、类的职责是否越单一越好?
单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。
- 但是如果拆分得过细,可能会适得其反,反倒会降低内聚性,也会影响代码的可维护性
比如,序列化这个功能可以拆分成2个类(一个序列化类,一个反序列化类),但是:
- 拆分成 2 个类,那序列化这整个功能就有点违反了“高内聚”的原则
- 序列化算法发生了改变,需要同时修改 2 个类的实现,在“可维护性”上也变差了
所以不是拆分得越细越好,要恰到好处的均衡。
- 不管怎么样,最终目的还是为了提高代码的可读性、可扩展性、复用性、可维护性等
在考虑应用某一个设计原则是否合理的时候,也可以以此作为最终的考量标准。