2. 工厂方法模式(Factory Method)

问题:创建对象的逻辑分散在各处,想统一管理。

核心:把 new 的过程封装到工厂函数里,调用者不关心具体类。

interface Pet {
  speak(): string;
}

class Dog implements Pet {
  speak(): string { return '汪汪'; }
}

class Cat implements Pet {
  speak(): string { return '喵喵'; }
}

type PetType = 'dog' | 'cat';

function createPet(type: PetType): Pet {
  switch (type) {
    case 'dog': return new Dog();
    case 'cat': return new Cat();
    default: throw new Error(`未知类型: ${type}`);
  }
}

const pet = createPet('dog');
console.log(pet.speak()); // 汪汪
package factory

import "fmt"

type Pet interface {
  Speak() string
}

type Dog struct{}
func (d Dog) Speak() string { return "汪汪" }

type Cat struct{}
func (c Cat) Speak() string { return "喵喵" }

func CreatePet(kind string) (Pet, error) {
  switch kind {
  case "dog":
    return Dog{}, nil
  case "cat":
    return Cat{}, nil
  default:
    return nil, fmt.Errorf("未知类型: %s", kind)
  }
}

实战场景

  • 通知渠道创建:根据 emailsmswebhookpush 创建不同发送器,业务代码只调用统一的 send()
  • 支付方式接入:根据订单选择支付宝、微信、银行卡、Stripe 等支付客户端,把创建细节和鉴权参数封装起来。
  • 文件解析器:上传 .csv.json.xlsx.xml 时,根据文件类型创建对应 parser,调用者只关心解析后的结构化数据。
  • 导出器生成:后台报表按用户选择导出 PDF、Excel、CSV 或图片,工厂负责返回不同 exporter。
  • UI 组件创建:低代码平台、表单引擎或配置化页面根据 type: 'input' | 'select' | 'date' 创建不同控件。
  • 数据库驱动选择:根据配置创建 MySQL、PostgreSQL、SQLite 或测试用内存数据库连接。
  • 第三方 API 客户端:同一个业务能力可能有多个供应商,例如短信、地图、对象存储,工厂根据地区或租户返回对应客户端。
  • 测试替身创建:测试环境返回 fake client 或 mock repository,生产环境返回真实实现,业务层不需要知道自己拿到的是哪一种。
  • 领域对象恢复:从数据库记录或消息队列 payload 恢复不同类型的领域对象,例如普通订单、预售订单、退款单。
  • 插件系统:根据插件 manifest 的类型加载不同插件实例,让新增插件时只扩展工厂映射,而不是改散落在各处的 new