单一职责原则(SRP)
在面向对象编程中,单一职责原则规定,每个类应该有一个责任,这个责任应该由类完全封装。它的所有服务应向责任狭义看齐....
简单总结:
一个类或模块应该有一个且只有一个理由去改变。
SRP案例
public class ForumService{
addThread(Thread thread);
addReplyMessage(Message message);
}
在上面论坛服务接口有两个方法,分别是增加一个主题addThread和增加一个回帖addReplyMessage,这是代表两个功能,那么这两个功能是否属于同一种职责呢?这需要从论坛这个模型结构考虑,如下:
Forum ---->Thread ------>Message
一个论坛Forum中有多个Thread,一个Thread包含一个根贴和多个回帖。
根据这种层次结构,增加回帖addReplyMessage的职责应该属于Thread,放入Forum中有点管得太宽了。
SRP好处
- 组织代码
让我们想象一个汽车修理工。 他使用很多工具一起工作。这些工具按类型分为:钳子,螺丝刀(十字/刀片),锤子,扳手(管/六角)等,他如何组织管理这些工具呢?他使用许多小抽屉将这些工具分门别类存放,这些抽屉其实类似模块作用,专门用来管理各种类。 - 减少脆弱
当一个类有多个理由需要修改时,它变得脆弱,在一个地方的修改会导致其他地方不可预期的后果。. - 更松耦合
更多职责责任导致更高的耦合。
耦合也是一种责任
高度耦合导致高度依赖,意味着难以维护。 - 代码改变
对于单一职责模块重构更容易.
如果你想获得猎枪的效果,就让你的类有更多职责。 - 维护性
维护一个单一职责的类比维护一个铁板一块的类更容易。 - 易于测试
测试单一目标的类只需要很少的测试类。让“用测试替代文档” “self documentation by tests”变得更加容易
- 易于调试
在一个单一职责类找到问题是一件更容易的事情。
哪些地方需要单一责任?
- 方法
- 类
- 包
- 模块
如何识别SRP被破坏?
- 类有太多依赖
类的构造器有太多参数,意味着测试有太多依赖,需要制造mock太多测试输入参数,通常意味着已经破坏SRP了。 - 方法有太多参数
类似类的构造器,方法参数意味着依赖。 - 测试类变得复杂
如果测试有太多变量,意味着这个类有太多职责。 - 类或方法太长
如果方法太长,意味着内容太多,职责过多。
一个类不超过 200-250 - 描述性名称
如果你需要描述你的类 方法或包,比如使用"xxx和xxx"这种语句,意味着可能破坏了SRP. - 低聚合Cohesion的类
聚合Cohesion是一个很重要的概念,虽然聚合是有关结构概念,但是聚合和SRP非常相关,如前面论坛案例,如果一个类不代表一个高聚合,意味着低凝聚low Cohesion,它就可能意味破坏SRP。一个低凝聚的特点:
一个类有两个字段,其中一个字段被一些方法使用;另外一个字段被其他方法使用。 - 在一个地方改动影响另外一个地方
如果在一个代码地方加入新功能或只是简单重构,却影响了其他不相关的地方,意味着这个地方代码可能破坏了SRP. - 猎枪效果Shotgun Effect
如果一个小的改变引起一发动全身,这意味SRP被破坏了。 - 不能够封装模块
比如使用Spring框架,你使用@Configuration or XML 配置,如果你不能在一个配置中封装一个Bean。意味着它有太多职责,Spring配置应该隐藏内部bean,暴露最少接口,如果你因为多个原因需要改变Spring配置,可能破坏了SRP.
更多相关话题讨论