正在加载,请稍候…

TypeScript 中的 SOLID 原则:实用示例

在真实的 TypeScript 项目中应用 SOLID 原则,通过具体示例学习单一职责、开闭、里氏替换、接口隔离和依赖反转原则

TypeScript 中的 SOLID 原则:实用示例

TypeScript 中的 SOLID 原则:实用示例

SOLID 原则指导您设计可维护、灵活的面相对象设计。

单一职责原则(SRP)

每个类应该只有一个变更原因。

// 不好:UserService 做了太多事情
class UserService {
  saveUser(user: User) { /* 数据库逻辑 */ }
  sendWelcomeEmail(user: User) { /* 邮件逻辑 */ }
  generateReport(userId: string) { /* 报告逻辑 */ }
}

// 好:分离关注点
class UserRepository {
  async save(user: User): Promise<void> { /* 数据库逻辑 */ }
  async findById(id: string): Promise<User | null> { /* 数据库逻辑 */ }
}

class EmailService {
  async sendWelcome(user: User): Promise<void> { /* 邮件逻辑 */ }
}

class UserReportService {
  async generate(userId: string): Promise<Report> { /* 报告逻辑 */ }
}

TypeScript 中的 SOLID 原则:实用示例插图

开闭原则(OCP)

对扩展开放,对修改关闭。

// 不好:添加新折扣类型需要修改现有代码
class DiscountCalculator {
  calculate(type: string, price: number): number {
    if (type === 'seasonal') return price * 0.9;
    if (type === 'member') return price * 0.85;
    // 每种新类型都需要修改此类
    return price;
  }
}

// 好:通过新实现进行扩展
interface DiscountStrategy {
  apply(price: number): number;
}

class SeasonalDiscount implements DiscountStrategy {
  apply(price: number): number { return price * 0.9; }
}

class MemberDiscount implements DiscountStrategy {
  apply(price: number): number { return price * 0.85; }
}

class PriceCalculator {
  constructor(private discount: DiscountStrategy) {}
  calculate(price: number): number {
    return this.discount.apply(price);
  }
}

TypeScript 中的 SOLID 原则:实用示例插图

里氏替换原则(LSP)

子类型必须能够替换其基类型。

// 不好:Square 破坏了 Rectangle 的行为
class Rectangle {
  setWidth(w: number) { this.width = w; }
  setHeight(h: number) { this.height = h; }
  area(): number { return this.width * this.height; }
  protected width = 0;
  protected height = 0;
}

class Square extends Rectangle {
  setWidth(w: number) { this.width = this.height = w; } // 违反 LSP!
  setHeight(h: number) { this.width = this.height = h; }
}

// 好:分离抽象
interface Shape {
  area(): number;
}

class Rectangle implements Shape {
  constructor(private width: number, private height: number) {}
  area(): number { return this.width * this.height; }
}

class Square implements Shape {
  constructor(private side: number) {}
  area(): number { return this.side ** 2; }
}

TypeScript 中的 SOLID 原则:实用示例插图

接口隔离原则(ISP)

不要强迫客户端依赖它们不使用的接口。

// 不好:胖接口
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
}

// 好:分离的接口
interface Workable {
  work(): void;
}

interface Eatable {
  eat(): void;
}

interface Sleepable {
  sleep(): void;
}

class HumanWorker implements Workable, Eatable, Sleepable {
  work() { /* ... */ }
  eat() { /* ... */ }
  sleep() { /* ... */ }
}

class Robot implements Workable {
  work() { /* ... */ }
  // 机器人不需要 eat/sleep
}

依赖反转原则(DIP)

依赖抽象,而非具体实现。

// 不好:高层依赖低层
class OrderService {
  private db = new MySQLDatabase(); // 具体依赖!
  async createOrder(order: Order): Promise<void> {
    await this.db.insert('orders', order);
  }
}

// 好:依赖抽象
interface Database {
  insert(table: string, data: unknown): Promise<void>;
  query<T>(sql: string, params: unknown[]): Promise<T[]>;
}

class OrderService {
  constructor(private db: Database) {} // 注入抽象
  async createOrder(order: Order): Promise<void> {
    await this.db.insert('orders', order);
  }
}

// 在组合根中组装
const db = new PostgreSQLDatabase(config);
const orderService = new OrderService(db);

SOLID 原则共同作用,创建易于测试、扩展和维护的系统。