代码规范 -- 单一原则

91 阅读2分钟

给的例子是反例和正例的比较,目的是展示函数功能单一性原则。

反例:

function emailClients(clients) {
  clients.forEach(client => {
    let clientRecord = database.lookup(client);
    if (clientRecord.isActive()) {
      email(client);
    }
  });
}

这个函数做了两件事:

  1. 查找数据库记录
  2. 判断客户是否活跃
  3. 发送邮件

这违反了单一职责原则,因为一个函数做了太多不同的事情,难以理解、测试和重构。

正例:

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();
}

这个版本遵循了单一职责原则:

  1. emailClients 只做遍历,调用其他函数来处理逻辑
  2. emailClientIfNeeded 只负责决定是否发送邮件
  3. isClientActive 只负责检查客户是否活跃,数据库查找与状态判断分开,职责清晰

我的理解:

拆分成多个小函数是为了确保每个函数只做一件事,这样代码的可维护性和可重构性都更强。每个函数都聚焦于单一功能,测试也变得更容易。
所以,正例是一个改进的方案,因为它符合单一职责原则,让代码更易于理解和修改。

总结:

你的反例和正例的设计思路很清楚,正例的拆分更加符合现代编程中的最佳实践,能够提高代码的可维护性和可读性。这种拆分我认为是非常好的!

虽然代码行数变多了,但意图确实更清晰了,尤其是在循环逻辑里更容易理解。

在循环中,代码如果做太多事情,就会导致:

  • 可读性差:别人看到 emailClients 可能需要花时间理解它到底做了什么。
  • 难以修改:如果后续需求变更,比如要记录日志缓存查询结果,拆分的版本会更容易调整。
  • 难以测试:在原来的版本里,想单独测试“客户是否活跃”这部分逻辑会很麻烦,但拆分后,我们可以直接测试 isClientActive,不用关心 emailClients 的循环逻辑。

循环中的代码为什么要拆分?

当代码在 循环 里做了太多事情时,拆分能带来这些好处:

  1. 减少嵌套,让逻辑扁平化(避免 if 语句嵌套得太深)。
  2. 提高代码复用性,比如 isClientActive 可能在其他地方也有用。
  3. 减少思维负担,让 emailClients 只关注“遍历”,而不是“判断+数据库查询+发送邮件”。

虽然代码行数变多了,但整体意图更清晰,维护成本更低,这正是好的代码设计应该追求的。

你觉得在你自己写代码的时候,会不会遇到类似的情况?