TS手写设计模式①:5个创建型模式写透,带你重构组件脑袋

169 阅读5分钟

本文是「TS手写设计模式」系列的第一篇,带你用TypeScript手把手实现所有5种创建型设计模式,包括:单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。每种模式不仅提供完整代码、UML类图,还结合前端场景与DSL系统落地应用,深入浅出,带你真正理解设计思想,而不仅是死记套路。

GitHub 项目地址 👉 cynthiaCh/design-patterns-ts


🔍 为什么要学习创建型模式?

在我们的前端项目中,你是否遇到过这些问题:

  • 组件初始化逻辑冗余、难以维护?
  • 表单字段配置混乱、创建方式不统一?
  • 多个主题皮肤 / 地域配置需要灵活切换?

这些问题,其实都可以归结为:“对象如何被创建” 的问题,也正是创建型模式要解决的核心。

创建型模式的目标是 将对象的创建过程从使用者中剥离出来,实现代码的高内聚、低耦合,为我们构建灵活可扩展的前端架构(特别是通用性开发和DSL场景)提供了极大帮助。

✅ 1. 单例模式 Singleton

🧠 核心思想

确保一个类只有一个实例,并提供一个全局访问点。是一种最简单却经久不衰的设计模式。

🧪 TypeScript 实现

export class Singleton {
  private static instance: Singleton
  private constructor() {}
  static getInstance() {
    if (!this.instance) this.instance = new Singleton()
    return this.instance
  }
  say() {
    return 'I am the only instance'
  }
}

🧩 场景类比

就像浏览器的 window 或 Vue 中的 Vuex store,我们希望某些全局状态是唯一的。

✅ 使用场景

  • 日志记录器(Logger)
  • 网络连接池(HTTP Client)
  • 全局配置中心

🧠 在组件系统中这样用

我们常常希望一些全局服务组件只存在一个实例,比如:

  • 全局 Loading 控制器:用于统一控制加载状态 LoadingController.getInstance().show()
  • 全局 Message / Toast 工具:避免重复弹窗、管理队列
  • DSL 运行上下文管理器:统一注册变量、响应事件(可复用)
export class LoadingController {
  private static instance: LoadingController
  private constructor() {}
  static getInstance() {
    if (!this.instance) this.instance = new LoadingController()
    return this.instance
  }
  show() {/*...*/} hide() {/*...*/}
}

✅ 2. 工厂方法模式 Factory Method

🧠 核心思想

将创建对象的逻辑延迟到子类中实现。我们只关心“创建一个什么类型的产品”,而不关心“如何创建”。

📌 传统写法的问题

function createFruit(type: string) {
  switch(type) {
    case 'apple': return new Apple()
    case 'banana': return new Banana()
  }
}

这种写法一旦要添加新类型,就得改 switch,违反了开闭原则。

✅ 工厂方法优化

interface Fruit {
  eat(): void
}
abstract class FruitCreator {
  abstract factoryMethod(): Fruit
}
class AppleCreator extends FruitCreator {
  factoryMethod(): Fruit {
    return new Apple()
  }
}

🧩 应用场景

  • 动态创建不同类型组件(比如不同输入组件)
  • 字段渲染器(fieldRenderer)注册与生成

🧠 在组件系统中这样用

当我们在构建表单 DSL 时,经常根据字段类型动态渲染不同组件:

class FieldFactory {
  static create(type: string): Component {
    switch (type) {
      case 'input': return new InputField()
      case 'select': return new SelectField()
    }
  }
}

更优方式是将构建逻辑写到子类中,并注册 creator map,支持插件化扩展和解耦。适用于你在 DSL 中构建「类型 = 渲染器」的结构。

✅ 3. 抽象工厂模式 Abstract Factory

🧠 核心思想

定义多个相关或依赖的对象创建接口,而无需指定它们具体的类。适用于“产品族”的场景。

示例

interface FruitFactory {
  createApple(): Apple
  createBanana(): Banana
}

class ChinaFruitFactory implements FruitFactory {
  createApple() { return new ChinaApple() }
  createBanana() { return new ChinaBanana() }
}

🧩 应用类比

  • Ant Design 不同主题的样式组件(暗色、亮色)
  • 根据“地域、行业”等创建不同 DSL 字段组件组合

✅ 优点

  • 保证产品之间组合一致性
  • 易于扩展,支持多套版本共存

🧠 在系统中这样用

当你要为不同“产品线/国家/主题”构建一套组件库,比如:

interface FormFactory {
  createTextField(): TextField
  createSelectField(): SelectField
}

class CNFormFactory implements FormFactory { /* 红色中文主题 */ }
class USFormFactory implements FormFactory { /* 英文蓝色主题 */ }

在实际项目中,这让你轻松切换 DSL 渲染策略,而无需侵入式修改组件。

✅ 4. 建造者模式 Builder

🧠 核心思想

将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

✨ 示例代码

const field = new FieldBuilder()
  .setType('select')
  .setLabel('省份')
  .setOptions(['北京', '上海'])
  .setRequired(true)
  .build()

💡 使用优势

  • 链式调用,简洁清晰
  • 拆解复杂构建流程
  • 支持字段 DSL 的灵活配置

🧩 场景例子

  • 表单构造器(FormBuilder)
  • JSON Schema 构造器

🧠 在 DSL 系统中这样用

构造一个字段配置常常是个冗长的对象:

const field = {
  type: 'select', label: '省份', required: true, options: [...]
}

使用建造者后:

new FieldBuilder()
  .setType('select')
  .setLabel('省份')
  .setOptions([...])
  .build()

优点:DSL 配置更清晰,字段支持默认注入、自定义生成逻辑。

✅ 5. 原型模式 Prototype

🧠 核心思想

用一个已经存在的实例作为原型,创建一个和它相似的新对象。常用于“复制”而非“新建”。

✅ TS实现

interface Prototype<T> {
  clone(): T
}

class Field implements Prototype<Field> {
  constructor(public label: string) {}
  clone(): Field {
    return new Field(this.label)
  }
}

🧩 应用场景

  • 表单模板复制功能
  • 低代码平台拖拽生成多个字段副本
  • 低代码编辑器中的“克隆模块”功能

🧠 在表单/编辑器中这样用

用户在拖拽时经常有“克隆已有字段”的需求:

const newField = oldField.clone()

优于 JSON.parse/深拷贝方式,因为:

  • 可以定制 clone 行为(清除 ID、调整默认值)
  • 可维护性强,可读性好

🧠 小结

模式关键动机典型场景
Singleton全局唯一实例配置中心、日志系统
Factory Method延迟构造逻辑渲染器、工厂注册中心
Abstract Factory产品族构造主题切换、风格替换
Builder分步骤构造字段构造器、组件生成器
Prototype快速复制表单字段复制、DSL模板

这些模式看似“老生常谈”,但一旦深入理解、落地于实际项目结构中,就会成为你构建大型系统时的底层设计武器

🚀 下一步计划

下一篇我们将进入「结构型模式」篇章,重点讲解:

  • 装饰器模式(字段增强)
  • 适配器模式(配置转换)
  • 外观模式(封装接口)

✨ 如果你正在构建 DSL、字段引擎或中后台组件库,这一系列内容将极具启发。

欢迎 Star 项目支持继续更新 👉 GitHub仓库

也欢迎关注掘金《TS手写设计模式》系列,每周更新,深挖设计思想,重构认知体系。