面向对象设计 >> 当前页

单一职责原则(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.

SOLID面向对象设计原则

Java面向对象面试参考指南