知识卡片
SRP的真正含义是"只对一类行为者负责",而非"只做一件事"
内容
单一职责原则常被想当然地理解为”每个模块只做一件事”——这其实是另一个面向底层实现细节的设计原则(常用于把大函数重构成小函数),并非SRP的全貌。SRP的准确表述经历了一次关键的措辞演化:从”任何模块都应该有且仅有一个被修改的原因”,到”任何模块都应该只对一个用户或利益相关者负责”,最终定型为”任何软件模块都应该只对某一类行为者(actor)负责”——行为者指一个或多个对系统提出相似变更需求的人。这个定义的价值在于它揭示了一种隐蔽的耦合风险:某工资管理程序的Employee类把calculatePay()(财务部门制定,向CFO汇报)、reportHours()(人力资源部门制定,向COO汇报)、save()(DBA制定,向CTO汇报)三个服务不同行为者的函数放进同一个类,为避免重复代码把两者共用的”计算正常工时”逻辑抽成regularHours()共享函数——结果CFO团队要求修改这个共享函数的算法,程序员只注意到calculatePay()调用了它、没注意到reportHours()也在用,改动上线后COO团队的HR报表数据悄悄出错,造成公司几百万美元损失。这正是SRP要防止的场景:把不同行为者依赖的代码强行凑到一起,会让某个团队的变更需求意外波及另一个团队根本不知情的功能。类似地,同一份源码被不同团队为不同目的修改,也会导致频繁而危险的代码合并冲突,甚至连没被改动的第三方功能都可能被合并过程波及。
参考来源
- 位置:《架构整洁之道》第7章《SRP:单一职责原则》"反面案例1:重复的假象""反面案例2:代码合并"(源文件:_epub-src/text/part0012_split_001.html)
- 结论依据:原文纠正"SRP=每个模块只做一件事"的常见误解,给出"只对某一类行为者负责"的最终定义,并用Employee类三个函数共享regularHours()逻辑、CFO团队改动意外破坏COO团队报表的真实案例说明违反SRP导致的隐蔽耦合风险,直接支撑本卡片结论。
- 原始内容:任何一个软件模块都应该只对某一类行为者负责……calculatePay()函数调用了regularHours()函数,但可能不会注意到该函数会同时被reportHours()调用……HR 仍然在使用reportHours()产生的报表,随后就会发现他们的数据出错了!