
TypeScript 设计模式:实用指南
工厂模式
无需指定具体类即可创建对象。
interface Logger {
log(message: string): void;
error(message: string): void;
}
class ConsoleLogger implements Logger {
log(msg: string) { console.log(`[LOG] ${msg}`); }
error(msg: string) { console.error(`[ERR] ${msg}`); }
}
class FileLogger implements Logger {
constructor(private path: string) {}
log(msg: string) { /* 写入文件 */ }
error(msg: string) { /* 写入文件 */ }
}
class LoggerFactory {
static create(type: 'console' | 'file', options?: { path?: string }): Logger {
switch (type) {
case 'console': return new ConsoleLogger();
case 'file': return new FileLogger(options?.path ?? 'app.log');
default: throw new Error(`Unknown logger type: ${type}`);
}
}
}
const logger = LoggerFactory.create('console');
观察者模式
定义订阅机制以通知对象事件。
type EventMap = Record<string, unknown[]>;
class EventEmitter<T extends EventMap> {
private listeners = new Map<keyof T, Set<Function>>();
on<K extends keyof T>(event: K, listener: (...args: T[K]) => void): void {
if (!this.listeners.has(event)) {
this.listeners.set(event, new Set());
}
this.listeners.get(event)!.add(listener);
}
off<K extends keyof T>(event: K, listener: Function): void {
this.listeners.get(event)?.delete(listener);
}
emit<K extends keyof T>(event: K, ...args: T[K]): void {
this.listeners.get(event)?.forEach(l => l(...args));
}
}
// 使用示例
type OrderEvents = {
created: [order: Order];
shipped: [orderId: string, trackingCode: string];
delivered: [orderId: string];
};
class OrderService extends EventEmitter<OrderEvents> {
async createOrder(data: CreateOrderDto): Promise<Order> {
const order = await this.db.create(data);
this.emit('created', order); // 通知监听者
return order;
}
}
orderService.on('created', (order) => emailService.sendConfirmation(order));
orderService.on('shipped', (id, tracking) => notificationService.notify(id, tracking));
策略模式
定义一系列算法并使它们可互换。
interface SortStrategy<T> {
sort(data: T[]): T[];
}
class QuickSort<T> implements SortStrategy<T> {
sort(data: T[]): T[] {
if (data.length <= 1) return data;
const pivot = data[Math.floor(data.length / 2)];
const left = data.filter(x => x < pivot);
const mid = data.filter(x => x === pivot);
const right = data.filter(x => x > pivot);
return [...this.sort(left), ...mid, ...this.sort(right)];
}
}
class BubbleSort<T> implements SortStrategy<T> {
sort(data: T[]): T[] {
const arr = [...data];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
return arr;
}
}
class Sorter<T> {
constructor(private strategy: SortStrategy<T>) {}
setStrategy(strategy: SortStrategy<T>) { this.strategy = strategy; }
sort(data: T[]): T[] { return this.strategy.sort(data); }
}
装饰器模式
动态地向对象添加行为。
interface TextProcessor {
process(text: string): string;
}
class PlainText implements TextProcessor {
process(text: string): string { return text; }
}
abstract class TextDecorator implements TextProcessor {
constructor(protected wrapped: TextProcessor) {}
process(text: string): string { return this.wrapped.process(text); }
}
class UpperCaseDecorator extends TextDecorator {
process(text: string): string { return super.process(text).toUpperCase(); }
}
class TrimDecorator extends TextDecorator {
process(text: string): string { return super.process(text).trim(); }
}
// 组合装饰器
const processor = new UpperCaseDecorator(new TrimDecorator(new PlainText()));
processor.process(' hello world '); // 'HELLO WORLD'
仓储模式
将数据访问抽象到接口之后。
interface UserRepository {
findById(id: string): Promise<User | null>;
findByEmail(email: string): Promise<User | null>;
save(user: User): Promise<User>;
delete(id: string): Promise<void>;
findAll(filter: UserFilter): Promise<User[]>;
}
class PostgresUserRepository implements UserRepository {
constructor(private db: Database) {}
async findById(id: string): Promise<User | null> {
const rows = await this.db.query('SELECT * FROM users WHERE id = $1', [id]);
return rows[0] ? this.mapToUser(rows[0]) : null;
}
async save(user: User): Promise<User> {
const result = await this.db.query(
'INSERT INTO users (id, email, name) VALUES ($1, $2, $3) ON CONFLICT (id) DO UPDATE SET ...',
[user.id, user.email, user.name]
);
return this.mapToUser(result[0]);
}
private mapToUser(row: Record<string, unknown>): User {
return { id: row.id as string, email: row.email as string, name: row.name as string };
}
}
// 用于测试的内存实现
class InMemoryUserRepository implements UserRepository {
private users = new Map<string, User>();
async findById(id: string) { return this.users.get(id) ?? null; }
async save(user: User) { this.users.set(user.id, user); return user; }
async delete(id: string) { this.users.delete(id); }
async findByEmail(email: string) {
return [...this.users.values()].find(u => u.email === email) ?? null;
}
async findAll() { return [...this.users.values()]; }
}
模式是解决重复问题的方案,而不是强加于每个问题的蓝图。