本文档解释了 SOLID 设计原则中的第一个原则——单一职责原则(SRP)及其在 JavaScript 中的实现。SRP 侧重于确保类或函数只有一个修改的原因。有关所有 SOLID 原则的更广泛背景,请参阅 SOLID 原则。
单一职责原则指出,一个类或模块应该只有一个修改的原因。这意味着一个类在软件系统中应该只有一个工作或职责。
遵守 SRP 为代码质量和可维护性带来了多项好处
SRP 的常见违反行为是当一个类处理多个不同的关注点时。下面的示例展示了一个同时管理用户身份验证和用户设置的类
SRP 违反示例
为了遵守 SRP,将类拆分成独立的类,每个类只有一个职责
符合 SRP 的解决方案
单一职责原则也适用于函数。一个函数应该只做一件事,并且做好。
来源: README.md291-308
来源: README.md312-321
| 技术 | 描述 | 示例 |
|---|---|---|
| 类提取 | 将复杂的类拆分成多个更简单的类 | 将 UserSettings 分离为 UserAuth 和 UserSettings |
| 函数提取 | 将复杂的函数分解为更小、更专注的函数 | 将 emailClients 分解为 emailActiveClients 和 isActiveClient |
| 组合 | 通过组合简单、专注的组件来构建复杂的行为 | 在 UserSettings 中使用 UserAuth,而不是继承 |
| 依赖注入 | 接收依赖项,而不是创建它们 | 将身份验证服务传递给设置管理器,而不是在内部处理身份验证 |
来源: README.md1392-1436 README.md291-321
单一职责原则与其他 SOLID 原则协同工作
接口隔离原则(ISP)与 SRP 密切相关,因为 ISP 将单一职责概念应用于接口——使接口保持专注和最小化。
注意这些可能表明 SRP 违反的迹象
README.md 中的示例展示了如何将身份验证与设置管理分离
// Before: Violation of SRP
class UserSettings {
constructor(user) {
this.user = user;
}
changeSettings(settings) {
if (this.verifyCredentials()) {
// ...
}
}
verifyCredentials() {
// ...
}
}
// After: Following SRP
class UserAuth {
constructor(user) {
this.user = user;
}
verifyCredentials() {
// ...
}
}
class UserSettings {
constructor(user) {
this.user = user;
this.auth = new UserAuth(user);
}
changeSettings(settings) {
if (this.auth.verifyCredentials()) {
// ...
}
}
}
README 也演示了如何将 SRP 应用于函数
// Before: Violation of SRP
function emailClients(clients) {
clients.forEach(client => {
const clientRecord = database.lookup(client);
if (clientRecord.isActive()) {
email(client);
}
});
}
// After: Following SRP
function emailActiveClients(clients) {
clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {
const clientRecord = database.lookup(client);
return clientRecord.isActive();
}
来源: README.md300-321
遵守单一职责原则可以使代码更易于维护、测试和理解。通过确保每个组件只有一个职责,我们减少了复杂性,并使我们的代码库更能应对变化。请记住,SRP 并非旨在使事物尽可能小,而是为了实现关注点的正确分离和内聚。