给的例子是反例和正例的比较,目的是展示函数功能单一性原则。
反例:
function emailClients(clients) {
clients.forEach(client => {
let clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
这个函数做了两件事:
- 查找数据库记录
- 判断客户是否活跃
- 发送邮件
这违反了单一职责原则,因为一个函数做了太多不同的事情,难以理解、测试和重构。
正例:
function emailClients(clients) {
clients.forEach(client => {
emailClientIfNeeded(client);
});
}
function emailClientIfNeeded(client) {
if (isClientActive(client)) {
email(client);
}
}
function isClientActive(client) {
let clientRecord = database.lookup(client);
return clientRecord.isActive();
}
这个版本遵循了单一职责原则:
emailClients只做遍历,调用其他函数来处理逻辑emailClientIfNeeded只负责决定是否发送邮件isClientActive只负责检查客户是否活跃,数据库查找与状态判断分开,职责清晰
我的理解:
拆分成多个小函数是为了确保每个函数只做一件事,这样代码的可维护性和可重构性都更强。每个函数都聚焦于单一功能,测试也变得更容易。
所以,正例是一个改进的方案,因为它符合单一职责原则,让代码更易于理解和修改。
总结:
你的反例和正例的设计思路很清楚,正例的拆分更加符合现代编程中的最佳实践,能够提高代码的可维护性和可读性。这种拆分我认为是非常好的!
虽然代码行数变多了,但意图确实更清晰了,尤其是在循环逻辑里更容易理解。
在循环中,代码如果做太多事情,就会导致:
- 可读性差:别人看到
emailClients可能需要花时间理解它到底做了什么。 - 难以修改:如果后续需求变更,比如要记录日志或缓存查询结果,拆分的版本会更容易调整。
- 难以测试:在原来的版本里,想单独测试“客户是否活跃”这部分逻辑会很麻烦,但拆分后,我们可以直接测试
isClientActive,不用关心emailClients的循环逻辑。
循环中的代码为什么要拆分?
当代码在 循环 里做了太多事情时,拆分能带来这些好处:
- 减少嵌套,让逻辑扁平化(避免
if语句嵌套得太深)。 - 提高代码复用性,比如
isClientActive可能在其他地方也有用。 - 减少思维负担,让
emailClients只关注“遍历”,而不是“判断+数据库查询+发送邮件”。
虽然代码行数变多了,但整体意图更清晰,维护成本更低,这正是好的代码设计应该追求的。
你觉得在你自己写代码的时候,会不会遇到类似的情况?