TypeScript 中的 SOLID 原则:从 A 到 Z 的理论与实践

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么 SOLID 对 TypeScript 开发者很重要

SOLID 是 Robert Martin(鲍勃大叔)提出的面向对象编程的五个基本原则。在结合了静态类型和 JavaScript 灵活性的 TypeScript 中,应用 SOLID 原则可以创建可扩展、可测试且易于维护的应用程序。在本文中,我们将从理论基础和 TypeScript 实践示例两方面来剖析每个原则。



1. 单一职责原则 (SRP)

理论

一个类应该只有一个引起变化的原因。这意味着每个模块、类或函数只负责一项功能。



TypeScript 实践

考虑一个违反 SRP 的类,它同时管理用户和发送通知:



// ❌ 违反 SRPclass UserManager {  constructor(private name: string, private email: string) {}

saveUser(): void { console.log(`用户 ${this.name} 已保存到数据库`); }

sendWelcomeEmail(): void { console.log(`欢迎邮件已发送至 ${this.email}`); }}


分离职责后的修正版本:



// ✅ 遵守 SRPclass User {  constructor(public name: string, public email: string) {}}

class UserRepository { save(user: User): void { console.log(`用户 ${user.name} 已保存到数据库`); }}

class EmailService { sendWelcomeEmail(user: User): void { console.log(`欢迎邮件已发送至 ${user.email}`); }}


2. 开闭原则 (OCP)

理论

软件实体应对扩展开放,对修改关闭。换句话说,您应该能够在不修改现有代码的情况下添加新功能。



TypeScript 实践

针对不同客户类型计算折扣的示例:



// ❌ 违反 OCPclass DiscountCalculator {  calculateDiscount(customerType: string, amount: number): number {    if (customerType === 'regular') {      return amount * 0.1;    } else if (customerType === 'premium') {      return amount * 0.2;    } else if (customerType === 'vip') {      return amount * 0.3;    }    return 0;  }}


// ✅ 通过多态遵守 OCPinterface DiscountStrategy {  calculate(amount: number): number;}

class RegularDiscount implements DiscountStrategy { calculate(amount: number): number { return amount * 0.1; }}

class PremiumDiscount implements DiscountStrategy { calculate(amount: number): number { return amount * 0.2; }}

class DiscountCalculator { constructor(private strategy: DiscountStrategy) {}

calculate(amount: number): number { return this.strategy.calculate(amount); }}


3. 里氏替换原则 (LSP)

理论

程序中的对象应该可以被其子类型的实例替换,而不影响程序的正确性。简单来说:如果你有一个基类,它的任何子类都应该能在使用基类的任何地方正常工作。



TypeScript 实践

几何图形的经典示例:



// ❌ 违反 LSPclass Rectangle {  constructor(protected width: number, protected height: number) {}

setWidth(width: number): void { this.width = width; }

setHeight(height: number): void { this.height = height; }

getArea(): number { return this.width * this.height; }}

class Square extends Rectangle { setWidth(width: number): void { this.width = width; this.height = width; // 违反原则! }

setHeight(height: number): vo

博客

书籍推荐