工厂模式把对象的创建过程封装起来,调用方只需告诉工厂"要什么",不需要知道具体怎么 new。前端常见于:根据接口字段类型创建不同形状的数据模型、根据按钮类型创建不同样式组件、根据支付渠道创建不同支付处理器。本 demo 用 TypeScript 实现类型映射驱动的工厂:一个注册表把"类型标识"映射到"构造器",工厂函数根据标识返回对应实例,且返回类型自动收窄为对应子类。
// 工厂模式:类型映射驱动的对象创建
// 根据标识创建对应类型实例,返回类型自动收窄
// 1. 形状基类与子类
abstract class Shape {
abstract area(): number;
abstract describe(): string;
}
class Circle extends Shape {
constructor(public radius: number) { super(); }
area() { return Math.PI * this.radius ** 2; }
describe() { return '圆形 r=' + this.radius; }
}
class Rectangle extends Shape {
constructor(public w: number, public h: number) { super(); }
area() { return this.w * this.h; }
describe() { return '矩形 ' + this.w + 'x' + this.h; }
}
class Triangle extends Shape {
constructor(public base: number, public height: number) { super(); }
area() { return 0.5 * this.base * this.height; }
describe() { return '三角形底' + this.base + '高' + this.height; }
}
// 2. 类型映射表:标识 => 构造器(每种子类对应一组参数类型)
interface ShapeRegistry {
circle: typeof Circle;
rectangle: typeof Rectangle;
triangle: typeof Triangle;
}
// 3. 提取构造器参数元组类型
type CtorArgs<C> = C extends new (...args: infer A) => unknown ? A : never;
// 4. 实例类型
type Instance<C> = C extends new (...args: any[]) => infer I ? I : never;
// 5. 工厂函数:标识与参数元组强绑定,返回精确实例类型
function createShape<K extends keyof ShapeRegistry>(
type: K,
...args: CtorArgs<ShapeRegistry[K]>
): Instance<ShapeRegistry[K]> {
const registry: ShapeRegistry = {
circle: Circle,
rectangle: Rectangle,
triangle: Triangle,
};
const Ctor = registry[type];
return new Ctor(...args);
}
// 应用:参数类型与标识一一对应
const c = createShape('circle', 5); // Circle,参数 [number]
const r = createShape('rectangle', 4, 6); // Rectangle,参数 [number, number]
const t = createShape('triangle', 3, 8); // Triangle,参数 [number, number]
console.log(c.describe(), c.area().toFixed(2));
console.log(r.describe(), r.area());
console.log(t.describe(), t.area());
ShapeRegistry:把标识字符串映射到构造器类型,是工厂类型推导的源头;新增形状只需在注册表加一项,工厂函数签名自动更新。CtorArgs<C> 提取构造器参数:用 infer A 从 new (...args) => unknown 提取参数元组类型,让 createShape('circle', 5) 的参数个数与类型被精确约束。Instance<C> 提取实例类型:用 infer I 提取构造器的实例类型,工厂返回值自动收窄为 Circle/Rectangle/Triangle,而非笼统的 Shape。K extends keyof ShapeRegistry 让标识、参数元组、返回类型三者绑定到同一 K,传错参数个数立刻编译期报错。// 参数个数错误会被拦截
// createShape('circle', 5, 6);
// 报错:Circle 构造器只接收 1 个参数
// 标识拼错会被拦截
// createShape('circl', 5);
// 报错:circl 不在 keyof ShapeRegistry 中
// 返回类型精确收窄,可访问子类特有属性
const circle = createShape('circle', 10);
console.log(circle.radius); // 10,Circle 特有属性可访问
const rect = createShape('rectangle', 3, 4);
console.log(rect.w, rect.h); // 3 4,Rectangle 特有属性可访问
// 批量创建:用映射类型生成联合
type ShapeKind = keyof ShapeRegistry; // 'circle' | 'rectangle' | 'triangle'
// 配置驱动创建:常见于接口返回 type 字段
function fromConfig(cfg: { type: ShapeKind; args: number[] }) {
return createShape(cfg.type, ...(cfg.args as [number, number])); // 运行时灵活,类型需断言
}