S 单一原则
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;
//省略其他属性和方法...
}
这个类足够单一吗?
对于这个类有两种观点:
- 这个类包含的根用户相关的信息,所以属性和方法都是隶属于用户这样一个业务模型,满足单一职责
- 这个类中地址信息所占比的中较高,应该将根地址相关的属性重新拆分成一个独立的UserAddress类,UserInfo只保留除Address之外的其他信息,拆分之后两个类的职责更加单一
实际上,要从中做出选择,要具体根据实际的业务场景来区分。在社交产品中,用户的信息只是单纯的为了展示,而不做过多业务,那么UserInfo当前的设计就是合理的。但是,如何这个社交产品后期反正得不较好,之后又在产品中新增了电商模块,用户的地址信息还会用在电商物流中,那我们最好将地址信息从UserInfo中拆分出来,独立成用户物流信息(或者叫地址信息、收货信息等)
我们在进一步延伸一下,如果这个社交产品的公司发展的越来越好,公司内部又开发出了很多产品(APP),公司希望支持统一账号登录,也就是用户一个账号可以在公司内部所有的产品进行登录。这个时候我们就需要继续对UserInfo进行拆分,将根身份认证相关的信息(比如,email、telephone等)抽取成独立的类
从这个例子,可以总结出:
- 对单一职责的的确定性,在不同的应用场景、不同的需求背景下,对同一个类的职责是否单一的判定,可能都是不一样的。
- 在某种应用场景或当下的需求背景下,一个类的设计可能已经满足单一职责原则了,但如果换个应用场景或着在未来的某个需求背景下,可能就不满足了,需要继续拆分更细粒度的类。
- 综上所述,评价一个类的职责是否足够单一,我们并没有一个非常明确的、可以量化的标准,可以说,这是件非常主观、仁者见仁智者见智的事情。实际上,在真正的软件开发中,我们也没必要过于未雨绸缪,过度设计。所以,我们可以先写一个粗粒度的类,满足业务需求。随着业务的发展,如果粗粒度的类越来越庞大,代码越来越多,这个时候,我们就可以将这个粗粒度的类,拆分成几个更细粒度的类。这就是所谓的持续重构
听到这里,你可能会说,这个原则如此含糊不清、模棱两可,到底该如何拿捏才好啊?我这里还有一些小技巧,能够很好地帮你,从侧面上判定一个类的职责是否够单一。而且,我个人觉得,下面这几条判断原则,比起很主观地去思考类是否职责单一,要更有指导意义、更具有可执行性:
- 类中的代码行数、函数或属性过多,会影响代码的可读性和可维护性,我们就需要考虑对类进行拆分;
- 类依赖的其他类过多,或者依赖类的其他类过多,不符合高内聚、低耦合的设计思想,我们就需要考虑对类进行拆分;
- 私有方法过多,我们就要考虑能否将私有方法独立到新的类中,设置为 public 方法,供更多的类使用,从而提高代码的复用性;
- 比较难给类起一个合适名字,很难用一个业务名词概括,或者只能用一些笼统的 Manager、Context 之类的词语来命名,这就说明类的职责定义得可能不够清晰;
- 类中大量的方法都是集中操作类中的某几个属性,比如,在 UserInfo 例子中,如果一半的方法都是在操作 address 信息,那就可以考虑将这几个属性和对应的方法拆分出来
重点回顾今天的内容到此就讲完了。我们来一块总结回顾一下,你应该掌握的重点内容。
- 如何理解单一职责原则(SRP)?
一个类只负责完成一个职责或者功能。不要设计大而全的类,要设计粒度小、功能单一的类。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。
如何判断类的职责是否足够单一?
不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:
- 类中的代码行数、函数或者属性过多;类依赖的其他类过多,或者依赖类的其他类过多;
- 私有方法过多;
- 比较难给类起一个合适的名字;
- 类中大量的方法都是集中操作类中的某几个属性。
- 类的职责是否设计得越单一越好?
单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。