TypeScript 中的 SOLID 原则:实用示例
SOLID 原则指导你编写灵活、可维护的面向对象代码。
单一职责原则(SRP)
一个类应该只有一个引起变化的原因。
// 糟糕:同时处理用户数据和邮件发送
class UserService {
createUser(name: string, email: string) { /* ... */ }
sendWelcomeEmail(email: string) { /* ... */ }
generateReport() { /* ... */ }
}
// 良好:分离职责
class UserRepository {
create(user: User): Promise<User> { /* ... */ }
findById(id: string): Promise<User> { /* ... */ }
}
class EmailService {
sendWelcome(email: string): Promise<void> { /* ... */ }
}
class UserReportGenerator {
generate(): Report { /* ... */ }
}
开闭原则(OCP)
对扩展开放,对修改关闭。
// 糟糕:添加折扣类型需要修改类
class OrderCalculator {
calculate(order: Order): number {
if (order.type === 'regular') return order.total;
if (order.type === 'premium') return order.total * 0.9;
// 新增类型必须修改类
}
}
// 良好:通过扩展实现,无需修改
interface DiscountStrategy {
apply(total: number): number;
}
class RegularDiscount implements DiscountStrategy {
apply(total: number) { return total; }
}
class PremiumDiscount implements DiscountStrategy {
apply(total: number) { return total * 0.9; }
}
class BlackFridayDiscount implements DiscountStrategy {
apply(total: number) { return total * 0.7; }
}
class OrderCalculator {
constructor(private discount: DiscountStrategy) {}
calculate(order: Order): number {
return this.discount.apply(order.total);
}
}
里氏替换原则(LSP)
子类型必须能够替换其基类型。
// 糟糕:Square 破坏了 Rectangle 的约定
class Rectangle {
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
area() { return this.width * this.height; }
}
class Square extends Rectangle {
setWidth(w: number) { this.width = w; this.height = w; } // 违反 LSP!
}
// 良好:分离层次结构
interface Shape {
area(): number;
}
class Rectangle implements Shape { /* ... */ }
class Square implements Shape { /* ... */ }
接口隔离原则(ISP)
客户端不应依赖它们不使用的接口。
// 糟糕:臃肿的接口
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
// 良好:小而专注的接口
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
class Human implements Workable, Eatable, Sleepable { /* ... */ }
class Robot implements Workable { /* 只工作 */ }
依赖倒置原则(DIP)
依赖抽象,而非具体实现。
// 糟糕:依赖具体实现
class OrderService {
private db = new MySQLDatabase(); // 硬依赖
saveOrder(order: Order) { this.db.save(order); }
}
// 良好:依赖抽象
interface Database {
save<T>(data: T): Promise<void>;
find<T>(id: string): Promise<T>;
}
class OrderService {
constructor(private db: Database) {} // 注入
async saveOrder(order: Order) { await this.db.save(order); }
}
// 在应用根组合
const service = new OrderService(new PostgresDatabase());
SOLID 原则使系统更易于测试、扩展和维护。