如何在需联动执行多函数时遵循单一职责原则(SRP)
单一职责原则(SRP)有两种经典表述:
A module should be responsible to one, and only one, actor
(模块仅应对一个且唯一的参与者负责)
或者:
A class should have one and only one reason to change
(类应该只有一个变更的理由)
基于此,我理解函数应该仅完成一项任务。但当我需要始终连续执行两个或多个函数,且不想单独调用其中某一个时,该如何处理?
举例说明:
我有以下两个函数:
void createProduct(){/*...*/}; void notifyUsers(){/*...*/};
每次创建产品后我都需要通知用户。那么我应该创建如下新函数来替代分别调用这两个函数吗?
void createAndNotify(){ createProduct(); notifyUsers(); }
还是说这种做法违反了SRP,我应该每次都像这样分别调用两个函数?
createProduct(); notifyUsers();
解答
创建createAndNotify()这类组合函数完全不违反单一职责原则,反而这是对SRP的合理落地,核心原因如下:
1. 明确SRP的核心边界
SRP的核心是避免让一个模块/类/函数承担多个独立的职责,而不是禁止将多个单一职责的操作组合成一个更高层的业务流程。createAndNotify()的职责并不是同时做“创建产品”和“通知用户”,它的职责是完成“创建产品并通知用户”这个完整的业务动作——这是一个独立的、更高层的单一职责,底层的createProduct()和notifyUsers()依然各自保持独立职责,互不干扰。
2. 从变更理由验证合规性
按照SRP“只有一个变更理由”的标准来看:
createProduct()的变更理由仅为「产品创建逻辑需要调整」(比如新增字段、修改存储规则);notifyUsers()的变更理由仅为「通知逻辑需要调整」(比如切换通知渠道、修改通知内容);createAndNotify()的变更理由仅为「这个业务流程需要调整」(比如后续要求创建后先审核再通知,或者取消通知步骤)。
三个函数的变更理由完全独立,没有重叠,完全符合SRP的要求。
3. 从工程效率角度看合理性
如果每次都手动串联调用两个函数,会带来两个问题:
- 违反DRY原则(Don't Repeat Yourself):一旦后续流程需要调整(比如新增日志、加前置校验),你需要在所有调用点逐一修改,维护成本极高;
- 流程一致性风险:可能出现某个调用点漏写
notifyUsers()的情况,导致业务逻辑出错。
封装成createAndNotify()后,所有调用点只需调用这个函数,流程变更只需要修改这一处,既保证了代码复用,也能确保业务流程的一致性。
注意事项
需要避免的是:不要把createProduct()和notifyUsers()的逻辑直接硬写到createAndNotify()里,要保持底层函数的独立性。这样如果后续出现其他场景(比如仅创建产品不需要通知),依然可以单独调用createProduct(),不会影响原有逻辑。
举个更通俗的例子:你有boilWater()和steepTeaLeaves()两个函数,封装一个makeTea()来调用这两个函数,完全符合SRP——makeTea()的职责是完成“泡茶”这个完整流程,而烧水和泡茶的逻辑依然各自独立,互不影响。
内容的提问来源于stack exchange,提问作者Lucas Tomic

