TypeScript高级设计模式实战

编程技术

TypeScript高级设计模式实战

TypeScript作为JavaScript的超集,不仅提供了类型系统,还支持许多面向对象的高级特性。本文将深入探讨TypeScript中的高级设计模式及其实际应用。

装饰器模式

类装饰器

function Logger<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    constructor(...args: any[]) {
      super(...args);
      console.log(`Instance created: ${constructor.name}`);
    }
  };
}

@Logger
class UserService {
  constructor(private name: string) {}
}

const user = new UserService('John'); // 输出: Instance created: UserService

方法装饰器

function MeasureTime(
  target: any,
  propertyKey: string,
  descriptor: PropertyDescriptor
) {
  const originalMethod = descriptor.value;
  
  descriptor.value = async function (...args: any[]) {
    const start = performance.now();
    const result = await originalMethod.apply(this, args);
    const end = performance.now();
    console.log(`${propertyKey} took ${end - start} milliseconds`);
    return result;
  };
  
  return descriptor;
}

class DataService {
  @MeasureTime
  async fetchData() {
    // 模拟API调用
    await new Promise(resolve => setTimeout(resolve, 1000));
    return { data: 'result' };
  }
}

依赖注入

实现简单的DI容器

interface Constructor<T> {
  new (...args: any[]): T;
}

class Container {
  private services = new Map<string, any>();
  private singletons = new Map<string, any>();

  register<T>(token: string, constructor: Constructor<T>): void {
    this.services.set(token, constructor);
  }

  registerSingleton<T>(token: string, constructor: Constructor<T>): void {
    this.services.set(token, constructor);
    this.singletons.set(token, null);
  }

  resolve<T>(token: string): T {
    const constructor = this.services.get(token);
    if (!constructor) {
      throw new Error(`Service ${token} not found`);
    }

    if (this.singletons.has(token)) {
      if (!this.singletons.get(token)) {
        this.singletons.set(token, new constructor());
      }
      return this.singletons.get(token);
    }

    return new constructor();
  }
}

// 使用示例
interface IDatabase {
  query(sql: string): Promise<any[]>;
}

class MySQLDatabase implements IDatabase {
  async query(sql: string): Promise<any[]> {
    console.log(`Executing: ${sql}`);
    return [];
  }
}

class UserRepository {
  constructor(private db: IDatabase) {}

  async getUsers() {
    return this.db.query('SELECT * FROM users');
  }
}

const container = new Container();
container.registerSingleton('database', MySQLDatabase);
container.register('userRepository', UserRepository);

工厂模式

抽象工厂

interface Button {
  render(): void;
  onClick(callback: () => void): void;
}

interface Checkbox {
  render(): void;
  toggle(): void;
}

interface UIFactory {
  createButton(): Button;
  createCheckbox(): Checkbox;
}

class WindowsButton implements Button {
  render() {
    console.log('Rendering Windows button');
  }
  onClick(callback: () => void) {
    console.log('Windows button clicked');
    callback();
  }
}

class WindowsCheckbox implements Checkbox {
  render() {
    console.log('Rendering Windows checkbox');
  }
  toggle() {
    console.log('Windows checkbox toggled');
  }
}

class MacButton implements Button {
  render() {
    console.log('Rendering Mac button');
  }
  onClick(callback: () => void) {
    console.log('Mac button clicked');
    callback();
  }
}

class MacCheckbox implements Checkbox {
  render() {
    console.log('Rendering Mac checkbox');
  }
  toggle() {
    console.log('Mac checkbox toggled');
  }
}

class WindowsUIFactory implements UIFactory {
  createButton(): Button {
    return new WindowsButton();
  }
  createCheckbox(): Checkbox {
    return new WindowsCheckbox();
  }
}

class MacUIFactory implements UIFactory {
  createButton(): Button {
    return new MacButton();
  }
  createCheckbox(): Checkbox {
    return new MacCheckbox();
  }
}

// 使用工厂
function createUI(os: 'windows' | 'mac'): UIFactory {
  switch (os) {
    case 'windows':
      return new WindowsUIFactory();
    case 'mac':
      return new MacUIFactory();
    default:
      throw new Error('Unsupported OS');
  }
}

观察者模式

类型安全的EventEmitter

type EventMap = {
  [key: string]: (...args: any[]) => void;
};

class TypedEventEmitter<Events extends EventMap> {
  private listeners: { [K in keyof Events]?: Events[K][] } = {};

  on<K extends keyof Events>(
    event: K,
    listener: Events[K]
  ): () => void {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event]!.push(listener);

    return () => this.off(event, listener);
  }

  off<K extends keyof Events>(event: K, listener: Events[K]): void {
    if (!this.listeners[event]) return;
    const index = this.listeners[event]!.indexOf(listener);
    if (index > -1) {
      this.listeners[event]!.splice(index, 1);
    }
  }

  emit<K extends keyof Events>(
    event: K,
    ...args: Parameters<Events[K]>
  ): void {
    if (!this.listeners[event]) return;
    this.listeners[event]!.forEach(listener => listener(...args));
  }
}

// 定义事件类型
interface AppEvents {
  userLogin: (userId: string, username: string) => void;
  userLogout: (userId: string) => void;
  dataUpdated: (data: any) => void;
}

const eventBus = new TypedEventEmitter<AppEvents>();

// 订阅事件
const unsubscribe = eventBus.on('userLogin', (userId, username) => {
  console.log(`User ${username} (${userId}) logged in`);
});

// 触发事件
eventBus.emit('userLogin', '123', 'John Doe');

// 取消订阅
unsubscribe();

策略模式

支付策略示例

interface PaymentStrategy {
  pay(amount: number): Promise<boolean>;
  refund(transactionId: string): Promise<boolean>;
}

class AlipayStrategy implements PaymentStrategy {
  async pay(amount: number): Promise<boolean> {
    console.log(`Paying ${amount} via Alipay`);
    // 调用支付宝API
    return true;
  }

  async refund(transactionId: string): Promise<boolean> {
    console.log(`Refunding transaction ${transactionId} via Alipay`);
    return true;
  }
}

class WeChatPayStrategy implements PaymentStrategy {
  async pay(amount: number): Promise<boolean> {
    console.log(`Paying ${amount} via WeChat Pay`);
    // 调用微信支付API
    return true;
  }

  async refund(transactionId: string): Promise<boolean> {
    console.log(`Refunding transaction ${transactionId} via WeChat Pay`);
    return true;
  }
}

class CreditCardStrategy implements PaymentStrategy {
  async pay(amount: number): Promise<boolean> {
    console.log(`Paying ${amount} via Credit Card`);
    // 调用信用卡支付API
    return true;
  }

  async refund(transactionId: string): Promise<boolean> {
    console.log(`Refunding transaction ${transactionId} via Credit Card`);
    return true;
  }
}

class PaymentContext {
  private strategy: PaymentStrategy;

  setStrategy(strategy: PaymentStrategy): void {
    this.strategy = strategy;
  }

  async executePayment(amount: number): Promise<boolean> {
    if (!this.strategy) {
      throw new Error('Payment strategy not set');
    }
    return this.strategy.pay(amount);
  }

  async executeRefund(transactionId: string): Promise<boolean> {
    if (!this.strategy) {
      throw new Error('Payment strategy not set');
    }
    return this.strategy.refund(transactionId);
  }
}

// 使用策略模式
const paymentContext = new PaymentContext();

// 根据用户选择设置策略
paymentContext.setStrategy(new AlipayStrategy());
await paymentContext.executePayment(100);

paymentContext.setStrategy(new WeChatPayStrategy());
await paymentContext.executePayment(200);

总结

TypeScript的高级特性使得设计模式的实现更加类型安全和优雅。通过合理运用这些模式,可以:

  1. 提高代码复用性:通过抽象和接口实现代码的复用
  2. 增强可维护性:清晰的结构使得代码更易于维护
  3. 提升可扩展性:新功能的添加不会影响现有代码
  4. 改善可测试性:依赖注入和接口隔离便于单元测试

在实际项目中,应根据具体需求选择合适的设计模式,避免过度设计。