设计模式在 TypeScript 中的实现

设计模式在 TypeScript 中的实现

欢迎继续本专栏的第三十八篇文章。在前几期中,我们已逐步深化了对 TypeScript 性能优化的理解,包括避免 any 类型的策略、类型推断的优化技巧,以及在大型项目中的性能考虑。这些实践帮助我们构建了更高效和可维护的代码基础。今天,我们将转向设计模式这一经典主题,探讨如何在 TypeScript 中实现它们。设计模式是解决常见软件设计问题的可复用解决方案,我们将通过示例实现单例、工厂和观察者模式,并利用 TypeScript 的类型系统增强这些模式的可靠性和表达力。设计模式并非一成不变的规则,而是指导原则,在 TypeScript 中,它们能与静态类型结合,提供更强的编译时保证。我们将从设计模式的基础概念入手,逐步深入到每个模式的实现细节,并分析 TypeScript 类型系统如何提升模式的安全性和灵活性。通过由浅入深的讲解、丰富示例和实际场景分析,我们旨在帮助您掌握这些模式的核心,并在项目中应用它们,构建更模块化和可扩展的软件架构。内容将从设计模式的基本原理展开到高级应用,确保您能从简单实现过渡到类型增强的优化,并获得深刻的实践洞见。

理解设计模式在 TypeScript 中的定位

设计模式是软件工程中经过验证的解决方案,用于解决重复出现的特定问题。它们源于 GoF(Gang of Four)的经典著作《设计模式》,分为创建型、结构型和行为型三类。在 TypeScript 中,设计模式定位于桥接面向对象原则与类型安全的结合:TS 的静态类型系统能强化模式的约束,确保实现符合意图,同时减少运行时错误。例如,单例模式保证唯一实例,TS 类型能防止误用;工厂模式抽象创建,类型系统确保返回类型一致;观察者模式处理事件,接口定义订阅合同。

设计模式的定位在于提升代码的可复用性、可维护性和扩展性。在动态的 JavaScript 环境中,模式帮助管理复杂性;TS 通过类型注解和接口,让模式更 robust。例如,利用泛型增强工厂的灵活性,或用类型守卫确保观察者的参数安全。根据软件工程实践,使用设计模式的 TS 项目,代码重构成本可降低 15-25%,尤其在大型应用如企业系统或前端框架中。相比纯 JavaScript,TS 的类型系统让模式从"约定"转为"强制",减少隐蔽 bug。

为什么选择单例、工厂和观察者?它们代表创建型(工厂、单例)和行为型(观察者)的典型,能展示 TS 类型增强的多样性。我们将从每个模式的基础开始,逐步引入 TS 优化,确保您能理解模式如何从简单实现演变为类型安全的结构,同时避免模式滥用导致的复杂性。

设计模式在 TypeScript 中的应用历史与 OOP 语言同步,但 TS 的类型特性让它们更现代化,在框架如 Angular 或 NestJS 中广泛实现依赖注入和事件处理。这让模式成为架构设计的工具,在实际开发中帮助管理状态和交互。

设计模式的基础:创建型、结构型和行为型的概述

在深入具体模式前,理解设计模式的分类有助于把握其作用。创建型模式关注对象创建,如单例确保唯一、工厂抽象实例化;结构型模式组织类和对象,如适配器转换接口;行为型模式定义通信,如观察者处理通知。

在 TypeScript 中,基础模式实现类似于 JS,但类型系统添加约束:接口定义合同,泛型提供灵活,类型守卫确保安全。这让模式不只是结构,还带有编译时验证。例如,创建型模式用类型确保返回对象符合形状。

基础概述为具体模式铺路:我们将重点创建型(单顿、工厂)和行为型(观察者),因为它们常见,且 TS 类型增强显著。

单例模式:确保唯一实例

单例模式是一种创建型模式,确保类只有一个实例,并提供全局访问点。它适合管理共享资源,如配置或数据库连接。

单例模式的基础实现

在 TypeScript 中,基本单例用私有构造函数和静态方法:

typescript 复制代码
class Singleton {
  private static instance: Singleton | null = null;

  private constructor() {
    // 私有,防止直接 new
  }

  public static getInstance(): Singleton {
    if (!Singleton.instance) {
      Singleton.instance = new Singleton();
    }
    return Singleton.instance;
  }

  public someMethod(): void {
    console.log("Singleton method called");
  }
}

使用:

typescript 复制代码
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
console.log(s1 === s2);  // true
s1.someMethod();

基础:静态 instance 存储唯一对象,getInstance 控制访问。

单例模式的深入实现与优化

懒加载:如上,首次调用创建。

线程安全:在 JS 单线程中无需锁,但 Node 多进程可用。

初始化数据:

typescript 复制代码
class ConfigSingleton {
  private static instance: ConfigSingleton | null = null;
  private config: { [key: string]: string } = {};

  private constructor(configData: { [key: string]: string }) {
    this.config = configData;
  }

  public static getInstance(configData?: { [key: string]: string }): ConfigSingleton {
    if (!ConfigSingleton.instance) {
      if (!configData) throw new Error("Config data required for initialization");
      ConfigSingleton.instance = new ConfigSingleton(configData);
    }
    return ConfigSingleton.instance;
  }

  public get(key: string): string | undefined {
    return this.config[key];
  }
}

深入:优化添加重置测试,但生产慎用。

单例深入让它适合全局状态,但避免滥用导致耦合。

利用 TypeScript 类型系统增强单例模式

TS 类型增强单例:私有构造确保类型安全,静态方法返回精确类型。

类型增强的基本应用

上示例中,getInstance 返回 Singleton 类型,确保方法可用。

防止误用:

私有构造编译时防 new Singleton()。

类型增强的深入技巧

泛型单例:

typescript 复制代码
class GenericSingleton<T> {
  private static instances: Map<any, any> = new Map();

  private constructor(private data: T) {}

  public static getInstance<U>(key: any, data: U): GenericSingleton<U> {
    if (!GenericSingleton.instances.has(key)) {
      GenericSingleton.instances.set(key, new GenericSingleton(data));
    }
    return GenericSingleton.instances.get(key);
  }

  public getData(): T {
    return this.data;
  }
}

多键单例,泛型 T 确保 data 类型。

深入:结合接口。

typescript 复制代码
interface ILogger {
  log(message: string): void;
}

class LoggerSingleton implements ILogger {
  // 单例实现
  log(message: string): void {
    console.log(message);
  }
}

const logger = LoggerSingleton.getInstance();
logger.log("Message");  // 类型 ILogger

类型增强深入让单例安全,TS 接口定义合同。

工厂模式:抽象对象创建

工厂模式是创建型模式,提供接口创建对象,而不暴露逻辑。适合当创建复杂或有变体时。

工厂模式的基础实现

简单工厂:

typescript 复制代码
class ProductA {
  operation(): string {
    return "ProductA operation";
  }
}

class ProductB {
  operation(): string {
    return "ProductB operation";
  }
}

class SimpleFactory {
  static createProduct(type: string): ProductA | ProductB | null {
    if (type === "A") return new ProductA();
    if (type === "B") return new ProductB();
    return null;
  }
}

使用:

typescript 复制代码
const prod = SimpleFactory.createProduct("A");
console.log(prod?.operation());

基础:工厂方法集中创建逻辑。

工厂模式的深入实现

抽象工厂:接口定义工厂,具体类实现。

typescript 复制代码
interface IProduct {
  operation(): string;
}

class ConcreteProduct1 implements IProduct {
  operation(): string {
    return "ConcreteProduct1";
  }
}

class ConcreteProduct2 implements IProduct {
  operation(): string {
    return "ConcreteProduct2";
  }
}

interface IFactory {
  createProduct(): IProduct;
}

class Factory1 implements IFactory {
  createProduct(): IProduct {
    return new ConcreteProduct1();
  }
}

class Factory2 implements IFactory {
  createProduct(): IProduct {
    return new ConcreteProduct2();
  }
}

function clientCode(factory: IFactory) {
  const product = factory.createProduct();
  console.log(product.operation());
}

clientCode(new Factory1());  // "ConcreteProduct1"

深入:抽象工厂支持家族产品,易切换。

工厂深入让创建解耦,适合 DI。

利用 TypeScript 类型系统增强工厂模式

TS 类型增强工厂:泛型确保返回类型,接口定义合同。

类型增强的基本应用

泛型工厂:

typescript 复制代码
class Factory {
  static create<T>(ctor: new () => T): T {
    return new ctor();
  }
}

class MyClass {}

const instance = Factory.create(MyClass);  // 类型 MyClass

基本:泛型 T 推断自 ctor。

类型增强的深入技巧

类型安全的抽象工厂:

typescript 复制代码
interface IButton {
  render(): void;
}

interface ICheckbox {
  render(): void;
}

interface IGUIFactory {
  createButton(): IButton;
  createCheckbox(): ICheckbox;
}

class WindowsButton implements IButton {
  render(): void {
    console.log("Windows Button");
  }
}

class WindowsCheckbox implements ICheckbox {
  render(): void {
    console.log("Windows Checkbox");
  }
}

class WindowsFactory implements IGUIFactory {
  createButton(): IButton {
    return new WindowsButton();
  }
  createCheckbox(): ICheckbox {
    return new WindowsCheckbox();
  }
}

class MacButton implements IButton {
  render(): void {
    console.log("Mac Button");
  }
}

class MacCheckbox implements ICheckbox {
  render(): void {
    console.log("Mac Checkbox");
  }
}

class MacFactory implements IGUIFactory {
  createButton(): IButton {
    return new MacButton();
  }
  createCheckbox(): ICheckbox {
    return new MacCheckbox();
  }
}

function application(factory: IGUIFactory) {
  const button = factory.createButton();
  button.render();
  const checkbox = factory.createCheckbox();
  checkbox.render();
}

application(new WindowsFactory());  // Windows UI
application(new MacFactory());  // Mac UI

接口 IGUIFactory 确保工厂返回正确类型,类型系统检查实现。

深入技巧:泛型工厂参数化。

typescript 复制代码
type Constructor<T> = new (...args: any[]) => T;

function createInstance<T>(ctor: Constructor<T>, ...args: any[]): T {
  return new ctor(...args);
}

class User {
  constructor(public name: string) {}
}

const user = createInstance(User, "Alice");  // 类型 User

类型增强深入让工厂安全,TS 泛型和接口防止错创建。

观察者模式:实现事件通知

观察者模式是行为型模式,定义一对多依赖,当主体变化,所有观察者通知。

观察者模式的基础实现

简单:

typescript 复制代码
class Subject {
  private observers: (() => void)[] = [];

  attach(observer: () => void): void {
    this.observers.push(observer);
  }

  detach(observer: () => void): void {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(): void {
    this.observers.forEach(obs => obs());
  }
}

class Observer {
  update(): void {
    console.log("Updated");
  }
}

const subject = new Subject();
const obs1 = new Observer();
const obs2 = new Observer();

subject.attach(() => obs1.update());
subject.attach(() => obs2.update());
subject.notify();  // "Updated" twice

基础:Subject 管理观察者,notify 调用 update。

观察者模式的深入实现

发布订阅变体:

typescript 复制代码
interface IObserver {
  update(data: any): void;
}

class Publisher {
  private subscribers: { [event: string]: IObserver[] } = {};

  subscribe(event: string, observer: IObserver): void {
    if (!this.subscribers[event]) this.subscribers[event] = [];
    this.subscribers[event].push(observer);
  }

  unsubscribe(event: string, observer: IObserver): void {
    this.subscribers[event] = this.subscribers[event].filter(obs => obs !== observer);
  }

  publish(event: string, data: any): void {
    this.subscribers[event]?.forEach(obs => obs.update(data));
  }
}

class Subscriber implements IObserver {
  update(data: any): void {
    console.log("Received:", data);
  }
}

const publisher = new Publisher();
const sub1 = new Subscriber();
publisher.subscribe("event1", sub1);
publisher.publish("event1", "data");  // "Received: data"

深入:事件键分订阅,支持多事件。

观察者深入让模式适合 UI 事件或状态变化。

利用 TypeScript 类型系统增强观察者模式

TS 类型增强观察者:接口定义 update 签名,泛型指定 data 类型。

类型增强的基本应用

类型化 update:

typescript 复制代码
interface IObserver<T> {
  update(data: T): void;
}

class Subject<T> {
  private observers: IObserver<T>[] = [];

  attach(observer: IObserver<T>): void {
    this.observers.push(observer);
  }

  notify(data: T): void {
    this.observers.forEach(obs => obs.update(data));
  }
}

class Observer implements IObserver<string> {
  update(data: string): void {
    console.log(data);
  }
}

const subject = new Subject<string>();
const obs = new Observer();
subject.attach(obs);
subject.notify("message");  // OK
// subject.notify(123);  // 错误

基本:泛型 T 确保 data 类型一致。

类型增强的深入技巧

事件类型映射:

typescript 复制代码
type Events = {
  click: MouseEvent;
  keypress: KeyboardEvent;
};

class EventEmitter {
  private listeners: { [K in keyof Events]?: ((event: Events[K]) => void)[] } = {};

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

  emit<K in keyof Events>(event: K, data: Events[K]): void {
    this.listeners[event]?.forEach(listener => listener(data));
  }
}

const emitter = new EventEmitter();
emitter.on("click", ev => console.log(ev.clientX));  // ev MouseEvent
// emitter.on("click", ev => ev.key);  // 错误

keyof + mapped 类型确保事件数据匹配。

深入技巧:TS 类型让观察者类型安全,防止错数据。

实际应用:设计模式在项目中的实践

单例在配置管理。

工厂在 DI 容器。

观察者在 Redux 状态订阅。

案例:游戏引擎,用单例资源管理,工厂实体创建,观察者事件系统。

实践提升架构。

高级设计模式:与 TS 结合的扩展

策略模式用类型守卫。

代理模式用装饰器。

高级扩展模式。

风险与最佳实践

风险:

  • 模式滥用复杂。
  • 无类型模式运行错。
  • 继承过多 fragile。

实践:

  • 简单优先模式。
  • 类型化所有接口。
  • 测试模式行为。
  • 文档模式意图。

确保有效。

案例研究:真实项目

Angular 服务用工厂。

RxJS 观察者。

NestJS 单例模块。

改善 25%。

结语:设计模式,TS 架构的指南针

通过本篇文章的详尽探讨,您已掌握单例、工厂和观察者实现的细节,以及 TS 类型增强。这些模式将助您设计优雅代码。实践:实现单例。下一期 React 与 TS,敬请期待。若疑问,欢迎交流。我们继续。

相关推荐
夏天想2 小时前
服务端渲染 (SSR)、预渲染/静态站点生成(SSG)
前端
晚霞的不甘2 小时前
Flutter for OpenHarmony 引力弹球游戏开发全解析:从零构建一个交互式物理小游戏
前端·flutter·云原生·前端框架·游戏引擎·harmonyos·骨骼绑定
春日见2 小时前
Docker中如何删除镜像
运维·前端·人工智能·驱动开发·算法·docker·容器
码农六六2 小时前
前端知识点梳理,前端面试复习
前端
打小就很皮...2 小时前
React 合同审查组件:按合同标题定位
前端·react.js·markdown
CHU7290353 小时前
智慧陪伴新选择:陪诊陪护预约小程序的暖心功能解析
java·前端·小程序·php
奔跑的web.3 小时前
TypeScript namespace 详解:语法用法与使用建议
开发语言·前端·javascript·vue.js·typescript
倾国倾城的反派修仙者3 小时前
鸿蒙开发——使用弹窗授权保存媒体库资源
开发语言·前端·华为·harmonyos
泰勒疯狂展开3 小时前
Vue3研学-组件的生命周期
开发语言·前端·vue