首页/开发/代码质量与评审速查/单一职责原则 SRP(Single Responsibility Principle)
设计原则与模式62 条

单一职责原则 SRP(Single Responsibility Principle)

一个模块应该只有一个被修改的原因(Robert C. Martin 表述):把「一个类一个职责」落到「一个变化原因」,需求变化只影响相关模块;判断用变化轴而非代码行数。

SRP 讲的是什么

单一职责原则最常见的表述来自 Robert C. Martin:一个模块应该只有一个被修改的原因。他把「一个类一个职责」翻译成更可操作的说法——看变化方向:同一处代码如果因为报表需求、计费规则、存储方式等不同原因被反复修改,说明它承担了多个职责。判断依据是变化轴,而不是代码行数。

基本信息

核心表述只对一个变化原因负责
判断依据变化轴:谁的需求变化会导致它被改
信号同一个类因不同原因被反复修改,改动互相干扰
关联概念高内聚、低耦合,以及发散式变化这一坏味道

什么时候该拆

  • 同一个类里,不同角色的需求分别要求修改它。
  • 一次改动只是为了某一类使用者,却要重新编译或测试全部逻辑。
  • 类的变更原因在描述里要用「以及」连接(既算工资又存数据库又出报表)。
  • 单元测试需要搭建大量与当前测试无关的依赖。
  • 方法集合天然分成几组,组间几乎不互相调用。

按变化轴拆分

按变化轴拆分
// 之前:Employee 承担 算工资 + 存数据库 + 出报表
// 之后按变化原因拆开
class Employee { Money calculatePay(); }
class EmployeeRepository { void save(Employee e); }
class EmployeeReporter { String report(Employee e); }

职责拆分的收益与代价

方面收益代价
修改范围需求变化只影响对应模块跨模块调用增多,需要清晰边界
测试可针对单一职责写小测试需要为协作关系补集成测试
理解成本每个类更容易理解类数量增加,需要靠命名与包结构导航
过度拆分——类碎化,读一条业务链路要跳十个文件

常见误区

  • 把职责当成功能:同一主题下的多个方法通常仍属一个职责。
  • 按方法数量拆分:方法少但变化原因多,仍然是多职责。
  • 用技术分层(数据访问、服务、控制器)替代职责判断:业务原因仍会让类不断膨胀。
  • 追求每个类都只有一个方法:过度拆分让调用链变长,理解成本反而上升。
「职责」不是「功能」:一个类可以有多个方法,只要它们服务于同一个变化原因。
判断拆不拆的实用问法:这次需求变化会让哪些代码变动?如果答案是互不相关的两组,就该考虑拆。

易错点

  • 把职责拆得过细:类数量激增,读一条业务链路要跨十个文件。
  • 以技术层替代职责判断:按数据访问、服务分层后,仍然会因业务原因不断膨胀。
  • 为满足原则而拆:没有真实变化压力的拆分只会增加跳转成本。
  • 只改类名不改依赖方向:拆分后仍在互相直接引用,耦合没有下降。

数据来源与参考

  • Robert C. Martin(Uncle Bob)· SRP 论述(《Clean Architecture》等)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌