JavaScript中的SOLID原则:从A到Z的理论与实践
\n\n开发高质量的软件不仅需要掌握语言的语法,还需要理解架构原则。SOLID 是面向对象设计的五个基本原则,有助于创建灵活、可维护且可扩展的代码。在本文中,我们将结合实践示例,逐一剖析JavaScript(Node.js)环境下的每个SOLID原则。
\n\n什么是SOLID?
\n\nSOLID 这个缩写由罗伯特·C·马丁(Bob大叔)提出,包含以下原则:
\n\n- \n
- S — 单一职责原则 (Single Responsibility Principle) \n
- O — 开闭原则 (Open/Closed Principle) \n
- L — 里氏替换原则 (Liskov Substitution Principle) \n
- I — 接口隔离原则 (Interface Segregation Principle) \n
- D — 依赖倒置原则 (Dependency Inversion Principle) \n
这些原则具有通用性,适用于包括JavaScript在内的任何编程语言。下面我们逐一详细讲解。
\n\n1. 单一职责原则 (SRP)
\n\n定义:一个类或模块应该只有一个引起变化的原因。换句话说,每个模块只负责一个特定的任务。
\n\n反面示例:一个 UserService 类同时负责保存用户、发送邮件和生成报告。
// ❌ 违反SRP\nclass UserService {\n saveUser(user) {\n // 保存到数据库\n console.log('User saved');\n }\n\n sendEmail(user) {\n // 发送邮件\n console.log('Email sent to ' + user.email);\n }\n\n generateReport(user) {\n // 生成报告\n console.log('Report generated for ' + user.name);\n }\n}\n\n正确示例:将职责拆分到不同的类中。
\n\n// ✅ 遵循SRP\nclass UserRepository {\n save(user) {\n console.log('User saved');\n }\n}\n\nclass EmailService {\n send(user) {\n console.log('Email sent to ' + user.email);\n }\n}\n\nclass ReportGenerator {\n generate(user) {\n console.log('Report generated for ' + user.name);\n }\n}\n\n// 使用\nconst user = { name: '伊万', email: 'ivan@example.com' };\nconst userRepo = new UserRepository();\nconst emailService = new EmailService();\nconst reportGen = new ReportGenerator();\n\nuserRepo.save(user);\nemailService.send(user);\nreportGen.generate(user);\n\n现在每个类只有一个职责,一个模块的修改不会影响其他模块。
\n\n2. 开闭原则 (OCP)
\n\n定义:软件实体(类、模块、函数)应该对扩展开放,对修改关闭。
\n\n反面示例:一个计算图形面积的函数使用了条件语句。
\n\n// ❌ 违反OCP\nfunction calculateArea(shape) {\n if (shape.type === 'circle') {\n return Math.PI * shape.radius ** 2;\n } else if (shape.type === 'rectangle') {\n return shape.width * shape.height;\n }\n // 添加新图形时必须修改函数\n return 0;\n}\n\n正确示例:使用多态和继承。
\n\n// ✅ 遵循OCP\nclass Shape {\n area() {\n throw new Error('area() 方法必须被实现');\n }\n}\n\nclass Circle extends Shape {\n constructor(radius) {\n super();\n this.radius = radius;\n }\n\n area() {\n return Math.PI * this.radius ** 2;\n }\n}\n\nclass Rectangle extends Shape {\n constructor