单一职责原则

单一职责原则

单一职责原则(Single Responsibility PrincipleSRP)。

英文描述:

1
A class or module should have a single responsibility

中文翻译:

1
一个类或者模块只负责一个职责(或者功能)

一、如何理解单一职责原则(SRP)?

单一职责原则的含义:

  • 一个类只负责完成一个职责或者功能
  • 不要设计大而全的类,而是设计粒度小、功能单一的类

比如,一个类里既包含订单的一些操作,又包含用户的一些操作。

订单和用户是两个独立的业务领域,将它们的功能都放在同一个类中,那就违反了单一职责原则。

需要将这个类拆分成两个粒度更细、功能更加单一的两个类:订单类和用户类。

二、为什么要用单一职责原则?

  • 实现代码高内聚、低耦合
  • 提高代码的复用性、可读性、可维护性

三、如何判定类的职责是否足够单一?

大部分情况下,类里的方法是否归为同一类,并不是那么容易判定的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class UserInfo {
private long userId;
private String username;
private String email;
private String telephone;
private long createTime;
private long lastLoginTime;
private String avatarUrl;
private String provinceOfAddress; // 省
private String cityOfAddress; // 市
private String regionOfAddress; // 区
private String detailedAddress; // 详细地址
// ...省略其他属性和方法...
}

UserInfo 类的设计是否满足单一职责原则呢?

对于这个问题,有两种不同的观点:

  1. UserInfo 类中都是跟用户相关的信息,都隶属于用户这样一个业务模型,满足单一职责原则
  2. 地址信息所占的比重较高,可以拆分成独立的 UserAddress 类,拆分后的两个类的职责更单一

这 2 种观点都可以说是正确的。

类的职责是否足够单一,实际上并没有一个明确的、可量化的标准:

  • 不同应用场景下,对同一个类的职责是否单一的判定,可能都是不一样的

在某种应用场景下,一个类的设计可能已经满足单一职责原则了,但如果换个应用场景,可能就不满足了。

可以用一些侧面指标,来判定类的设计是否满足单一职责原则:

  • 类中的代码行数、函数或者属性过多,多到不知道用哪个的时候
  • 类依赖的其他类过多,或者依赖类的其他类过多
  • 私有方法过多,就要考虑能否将私有方法独立到新的类中
  • 比较难给类起一个合适的名字,或者只能用一些笼统的 Manager、Context 之类的词语来命名
  • 经常集中操作类中的某几个属性,可以考虑将这几个属性单独抽出来做成一个类

满足这些情况之一,就说明类设计不符合单一职责原则,需要拆分。

但是也不必过于未雨绸缪,刚开始时不必过度设计:

  • 可以先写一个粗粒度的类,暂时满足业务需求
  • 随着业务的发展,代码越来越多,再考虑拆分成几个更细粒度的类

这种方式就是所谓的持续重构。

四、类的职责是否越单一越好?

单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。

  • 但是如果拆分得过细,可能会适得其反,反倒会降低内聚性,也会影响代码的可维护性

比如,序列化这个功能可以拆分成2个类(一个序列化类,一个反序列化类),但是:

  • 拆分成 2 个类,那序列化这整个功能就有点违反了“高内聚”的原则
  • 序列化算法发生了改变,需要同时修改 2 个类的实现,在“可维护性”上也变差了

所以不是拆分得越细越好,要恰到好处的均衡。

  • 不管怎么样,最终目的还是为了提高代码的可读性、可扩展性、复用性、可维护性等

在考虑应用某一个设计原则是否合理的时候,也可以以此作为最终的考量标准。

作者

jiaduo

发布于

2022-11-05

更新于

2023-04-03

许可协议