单一职责原则(SRP)Single Responsibility Principle。
如何理解单一职责原则
A class or module should have a single reponsibility。翻译成中文就是,一个类或者模块只负责一个单独的职责(或功能)。这里原则的应用对象是类和模块,模块可以是一种更抽象的描述,也可以是多个类的集合。对于类来讲,遵循单一职责原则就是不要设计大而全的类,而要设计粒度小,功能单一的类。
单一职责原则是为了实现代码高内聚,低耦合,提高代码的复用性、可读性、可维护性。
如何判断类的职责是否足够单一
在真实的软件开发中,一般类的职责是否单一不是一眼就能识别的,并没有一个非常明确的,可以量化的标准,并不是说一个类包含多少行代码,多少个函数以内才说明类的职责足够单一。一般在不同的业务场景,不同的需求背景下,对类的职责是否单一的判定,都可能是不一样的。比如下面这个用户类。
public class UserInfo{
private String id;
private String username;
private String password;
private String email;
private String telephone;
private String avatarUrl;
private String province;
private String city;
private String region;
private String detailAddress;
private long createTime;
private long updateTime;
private String createdBy;
...
}
单看这个用户类,里面包含的信息都是用户信息,应该是符合类的单一职责原则的。如果这个用户类只是用来展示信息,不涉及其他功能,那可以说满足类的单一职责原则,但是随着业务的扩大,需求的变更,项目中其他一些模块都要用到用户的地址信息,比如订单的物流等,那这时候最好是将跟用户地址有关的几个字段拆分出来,单独成为一个用户地址信息,物流地址信息类。后面随着业务需求的变更,用户类也可能需要进一步拆分细化。
所以基于不用的业务场景,需求背景去看待一个类的职责是否单一,可能就会有不同的结论。实际上,在真实的业务开发中,我们也不必过于未雨绸缪,为未来买单,对类过度设计。我们可以在开发初期实现一个满足需求的粗粒度的类,随着业务的发展,如果类的代码越来越多,可以将粗粒度的类拆分成一个个细粒度的类,在开发过程中持续重构。那具体什么时候对类进行拆分重构呢?事实上是没有具体依据的,但以下几点可以作为参考:
- 类中属性或函数过多,致使类的行数过多,影响了代码的可读性,可维护性,可以考虑对类进行拆分
- 类依赖其他类过多,不符合高内聚,低耦合原则,可以考虑对类进行拆分
- 类的私有方法过多,可以考虑是否将私有方法提到一个类提供公有方法供其他类使用,提高代码的可复用性(如果私有方法也被其他类需要)。
- 类中大量方法都在集中操作类中的某几个属性,比如UserInfo类中,一半的方法都在操作地址信息,那可以考虑将地址信息及其操作方法拆分成一个单独的类。
- 当一个类读起来很费力,实现某一个功能不知道调用什么方法,或者方法找半天,可以考虑对类进行拆分
- 如果因为一个小功能需要引入一个大类,且类中包含很多无关此功能的方法,可以考虑对类进行拆分
类的职责是否设计得越单一越好
答案是否定的,单一职责原则通过避免将不相关的功能耦合在一起,来提高类的内聚性,减少代码的耦合,但是如果类拆分得过细,实际上会适得其反,会降低类的内聚性,影响代码的可维护性。还是需要结合具体开发场景具体分析,实际上,不管是设计原则还是设计模式,最终目的都是提高代码的可读性,可扩展性,复用性,可维护性等,在实际开发中,判断类是否设计的合理,都可以以这些为考量标准。