工厂模式 ⭐
定义
工厂模式(Factory Pattern):把“创建对象”这件事单独封装起来。
提供一种隐藏创建逻辑的对象创建方式,而不是通过直接 new 暴露实例化过程。
应用场景
- jQuery $
- React.createElement
- Vue render
- UI 组件库
- 动态表单
核心对比
简单工厂解决“创建问题”,工厂方法解决“扩展问题”,抽象工厂解决“产品族问题”。
| 模式 | 解决的核心问题 | 特点 / 痛点 | 前端常见场景 |
|---|---|---|---|
| 简单工厂 | 把 new 对象的过程封装起来。 |
只有一个万能工厂类。违背开闭原则,修改逻辑需改核心代码。 | 根据后端返回的 type 字段渲染不同的图表(Line, Bar, Pie)。 |
| 工厂方法 | 解决简单工厂违背开闭原则的问题。 | 把大工厂拆成无数小工厂(一类产品配一个工厂)。扩展性好,但类容易爆炸。 | 复杂框架的底层设计,如 Vue/React 源码中的不同节点的创建工厂。 |
| 抽象工厂 | 解决**“系列产品(产品族)”**的一致性创建问题。 | 一次性产出一整套具有相关性的产品。避免风格或环境不匹配。 | 暗黑/明亮主题组件库;小程序/H5跨平台多端 API 适配层。 |
简单工厂模式
建立一个专门的工厂类,里面包含一个大大的 if-else 或 switch。调用者只需传入一个参数(如产品名字),工厂就能帮你生产出对应的实例。
❌ 严重违背“开闭原则”(OCP)
js
// 基础产品类
class SuccessAlert { show() { console.log("显示成功绿色弹窗"); } }
class ErrorAlert { show() { console.log("显示失败红色弹窗"); } }
// 简单工厂类
class AlertFactory {
// 核心就是一个静态方法,根据参数返回不同对象
static createAlert(type) {
switch (type) {
case 'success':
return new SuccessAlert();
case 'error':
return new ErrorAlert();
default:
throw new Error("没这个类型的弹窗!");
}
}
}
// 业务调用(我不管你怎么new的,我只要个成功的弹窗)
const myAlert = AlertFactory.createAlert('success');
myAlert.show();
工厂方法模式 ⭐
定义
工厂方法模式(Factory Method Pattern),本意是将实际创建对象的工作推迟到子类中,这样核心类就变成了抽象类。
我们可以将工厂方法看作是一个实例化对象的工厂类。
✅ 完美符合“开闭原则”。
实现
ts
// 1. 抽象产品
interface IAlert { show(): void; }
// 2. 具体产品
class SuccessAlert implements IAlert { show() { console.log("成功弹窗"); } }
class ErrorAlert implements IAlert { show() { console.log("错误弹窗"); } }
// 3. 抽象工厂(核心:定义了造产品的规范,但不具体造)
interface IAlertFactory {
createAlert(): IAlert;
}
// 4. 具体工厂(一种产品对应一个工厂)
class SuccessAlertFactory implements IAlertFactory {
createAlert() { return new SuccessAlert(); }
}
class ErrorAlertFactory implements IAlertFactory {
createAlert() { return new ErrorAlert(); }
}
// 业务调用
// 假设这是成功的业务逻辑,我引入专门生产Success的工厂
const factory = new SuccessAlertFactory();
const alert = factory.createAlert();
alert.show();
抽象工厂模式
定义
抽象工厂模式(Abstract Factory Pattern),在工厂方法的基础上再抽象一层,用来管理多个工厂类,该超级工厂又称为其他工厂的工厂。
这是最复杂的一种。工厂方法关注的是“单个产品”(比如弹窗),而抽象工厂关注的是“产品族(一套相关的产品)”。
实现
ts
// --- 抽象产品族 ---
interface IButton { render(): void; }
interface IDialog { render(): void; }
// --- 具体产品 (Mac系列) ---
class MacButton implements IButton { render() { console.log("渲染 Mac 风格按钮"); } }
class MacDialog implements IDialog { render() { console.log("渲染 Mac 风格弹窗"); } }
// --- 具体产品 (Win系列) ---
class WinButton implements IButton { render() { console.log("渲染 Win 风格按钮"); } }
class WinDialog implements IDialog { render() { console.log("渲染 Win 风格弹窗"); } }
// === 核心:抽象工厂 (定义一套系列产品的生产线) ===
interface IThemeFactory {
createButton(): IButton;
createDialog(): IDialog;
}
// === 具体工厂 (按系列生产) ===
class MacThemeFactory implements IThemeFactory {
createButton() { return new MacButton(); }
createDialog() { return new MacDialog(); }
}
class WinThemeFactory implements IThemeFactory {
createButton() { return new WinButton(); }
createDialog() { return new WinDialog(); }
}
// --- 业务调用 ---
// 根据用户系统,只实例化一个工厂,就能保证产出的组件风格绝对统一!
function renderUI(factory: IThemeFactory) {
const btn = factory.createButton();
const dialog = factory.createDialog();
btn.render();
dialog.render();
}
// 如果是 Mac 用户:
renderUI(new MacThemeFactory());
// 打印:渲染 Mac 风格按钮 \n 渲染 Mac 风格弹窗