
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> { /* 报告逻辑 */ }
}
开闭原则(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);
}
}
里氏替换原则(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; }
}
接口隔离原则(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 原则共同作用,创建易于测试、扩展和维护的系统。