工厂模式核心概念解析
- 工厂模式 (Factory Pattern) 是一种创建型设计模式,核心思想是将对象的创建过程封装起来,用一个 “工厂” 类 / 函数来统一生产对象,而不是让调用方直接通过 new 关键字创建对象;
- 它解决的核心问题:
- 减少调用方与具体对象类的耦合 (调用方只需要告诉工厂 “要什么”,不用关心 “怎么造”);
- 统一管理对象的创建逻辑,便于后续扩展和维护;
- 隐藏对象创建的复杂细节 (比如初始化参数、依赖注入等);
工厂模式
三者的核心都是「把对象创建的逻辑封装起来」,区别仅在于「封装的粒度」:
- 简单工厂是「粗粒度」
- 工厂方法是「单产品粒度」
- 抽象工厂是「产品族粒度」
简单工厂模式(静态工厂)
-
最基础的实现,一个工厂函数根据传入的参数,直接创建并返回不同类型的对象 (不属于 GoF 23 种设计模式,但最常用);
-
类图:
-
场景选择:饮品店制作饮品,用户点单类型 (咖啡 / 奶茶) 直接创建对应的饮品,无需用户关心饮品的制作细节
// 抽象饮品类(定义所有饮品的通用方法) class Drink { make() { throw new Error("所有饮品必须实现制作方法"); } } // 具体产品:咖啡 class Coffee extends Drink { make() { return "制作咖啡:研磨咖啡豆 → 萃取浓缩液 → 加奶/糖 → 完成"; } } // 具体产品:奶茶 class MilkTea extends Drink { make() { return "制作奶茶:煮红茶 → 加鲜奶 → 调甜度 → 加珍珠 → 完成"; } } // 简单工厂:饮品工厂 class DrinkFactory { /** * 根据饮品类型创建饮品实例 * @param {string} type 饮品类型(coffee/milkTea) * @returns {Drink} 饮品实例 */ createDrink(type) { switch (type.toLowerCase()) { case "coffee": return new Coffee(); case "milktea": return new MilkTea(); default: throw new Error(`暂不支持制作 ${type} 这种饮品`); } } } // 测试代码(客户端:顾客点单) const drinkShop = new DrinkFactory(); const myCoffee = drinkShop.createDrink("coffee"); const myMilkTea = drinkShop.createDrink("milktea"); console.log("顾客点了咖啡:"); console.log(myCoffee.make()); // 输出:制作咖啡:研磨咖啡豆 → 萃取浓缩液 → 加奶/糖 → 完成 console.log("\n顾客点了奶茶:"); console.log(myMilkTea.make()); // 输出:制作奶茶:煮红茶 → 加鲜奶 → 调甜度 → 加珍珠 → 完成 -
场景解析:
- 顾客 (客户端) 只需要告诉饮品店 (工厂) 要「咖啡」或「奶茶」,无需自己动手制作;
- 如果新增饮品,需要修改 DrinkFactory 的 createDrink 方法 (违反开闭原则),这也是简单工厂的核心缺点;
工厂方法模式
-
将对象的创建延迟到子类中,核心是 “定义创建对象的接口,让子类决定实例化哪个类”,每个产品对应一个工厂子类;
-
类图:
-
场景选择:电商平台的支付方式,每种支付方式对应一个专属工厂 (支付宝工厂 / 微信支付工厂),新增支付方式只需新增「支付类 + 工厂类」,无需修改原有代码;
// 抽象产品:支付方式 class Payment { /** * 支付方法 * @param {number} amount 支付金额 * @returns {string} 支付结果 */ pay(amount) { throw new Error("所有支付方式必须实现支付方法"); } } // 具体产品:支付宝支付 class Alipay extends Payment { pay(amount) { return `支付宝支付 ${amount} 元:验证账号 → 扣减余额 → 支付成功`; } } // 具体产品:微信支付 class WechatPay extends Payment { pay(amount) { return `微信支付 ${amount} 元:调起微信小程序 → 输入密码 → 支付成功`; } } // 抽象工厂:支付工厂 class PaymentFactory { createPayment() { throw new Error("所有支付工厂必须实现创建支付方式的方法"); } } // 具体工厂:支付宝工厂 class AlipayFactory extends PaymentFactory { createPayment() { return new Alipay(); } } // 具体工厂:微信支付工厂 class WechatPayFactory extends PaymentFactory { createPayment() { return new WechatPay(); } } // 测试代码(客户端:用户选择支付方式) // 选择支付宝支付 const alipayFactory = new AlipayFactory(); const alipay = alipayFactory.createPayment(); console.log(alipay.pay(99)); // 输出:支付宝支付 99 元:验证账号 → 扣减余额 → 支付成功 // 选择微信支付 const wechatPayFactory = new WechatPayFactory(); const wechatPay = wechatPayFactory.createPayment(); console.log(wechatPay.pay(199)); // 输出:微信支付 199 元:调起微信小程序 → 输入密码 → 支付成功 // 新增支付方式:银联支付(无需修改原有代码,符合开闭原则) class UnionPay extends Payment { pay(amount) { return `银联支付 ${amount} 元:插卡 → 输入密码 → 支付成功`; } } class UnionPayFactory extends PaymentFactory { createPayment() { return new UnionPay(); } } const unionPayFactory = new UnionPayFactory(); const unionPay = unionPayFactory.createPayment(); console.log(unionPay.pay(299)); // 输出:银联支付 299 元:插卡 → 输入密码 → 支付成功 -
场景解析:
- 每种支付方式都有专属工厂,新增银联支付时,只需要新增 UnionPay (产品类) 和 UnionPayFactory (工厂类),完全不改动原有代码;
- 客户端需要先选择「支付工厂」,再通过工厂获取「支付方式」,逻辑更清晰,扩展性更强;
抽象工厂模式
-
用于创建一系列相关 / 依赖的对象簇,而不用指定具体类;
-
类图:
-
实现代码:
// 产品族 1:沙发(抽象类) class Sofa { sitOn() { throw new Error("所有沙发必须实现坐的方法"); } } // 产品族 2:茶几(抽象类) class CoffeeTable { putThings() { throw new Error("所有茶几必须实现放东西的方法"); } } // 现代风格 - 沙发 class ModernSofa extends Sofa { sitOn() { return "坐现代风格沙发:简约布艺,坐感偏硬"; } } // 现代风格 - 茶几 class ModernCoffeeTable extends CoffeeTable { putThings() { return "用现代风格茶几:钢化玻璃桌面,金属支架"; } } // 欧式风格 - 沙发 class EuropeanSofa extends Sofa { sitOn() { return "坐欧式风格沙发:雕花皮质,坐感柔软"; } } // 欧式风格 - 茶几 class EuropeanCoffeeTable extends CoffeeTable { putThings() { return "用欧式风格茶几:实木雕花桌面,雕花支架"; } } // 抽象工厂:家具工厂(定义创建所有家具的方法) class FurnitureFactory { createSofa() { throw new Error("必须实现创建沙发的方法"); } createCoffeeTable() { throw new Error("必须实现创建茶几的方法"); } } // 具体工厂 1:现代家具工厂(创建现代风格的所有家具) class ModernFurnitureFactory extends FurnitureFactory { createSofa() { return new ModernSofa(); } createCoffeeTable() { return new ModernCoffeeTable(); } } // 具体工厂 2:欧式家具工厂(创建欧式风格的所有家具) class EuropeanFurnitureFactory extends FurnitureFactory { createSofa() { return new EuropeanSofa(); } createCoffeeTable() { return new EuropeanCoffeeTable(); } } // 测试代码(客户端:顾客选择家具风格) // 选择现代风格家具套件 const modernFactory = new ModernFurnitureFactory(); const modernSofa = modernFactory.createSofa(); const modernTable = modernFactory.createCoffeeTable(); console.log("现代风格家具套件:"); console.log(modernSofa.sitOn()); // 输出:坐现代风格沙发:简约布艺,坐感偏硬 console.log(modernTable.putThings()); // 输出:用现代风格茶几:钢化玻璃桌面,金属支架 console.log("\n欧式风格家具套件:"); // 选择欧式风格家具套件 const europeanFactory = new EuropeanFurnitureFactory(); const europeanSofa = europeanFactory.createSofa(); const europeanTable = europeanFactory.createCoffeeTable(); console.log(europeanSofa.sitOn()); // 输出:坐欧式风格沙发:雕花皮质,坐感柔软 console.log(europeanTable.putThings()); // 输出:用欧式风格茶几:实木雕花桌面,雕花支架 -
场景解析:
- 抽象工厂解决的是「产品族」的问题:选择「现代工厂」就只能拿到现代沙发 + 现代茶几,不会出现「现代沙发配欧式茶几」的混搭情况,保证产品的一致性;
- 新增风格 (如中式风格) 只需新增「中式沙发 + 中式茶几 + 中式家具工厂」,无需修改原有代码;但如果新增家具类型 (如椅子),则需要修改抽象工厂和所有具体工厂 (这是抽象工厂的小缺点);
三种工厂模式的对比
| 特性 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 目的 | 创建单一产品 | 创建单一产品,但延迟到子类 | 创建产品族 |
| 复杂度 | 低 | 中 | 高 |
| 灵活性 | 低 | 中 | 高 |
| 扩展性 | 添加新产品需要修改工厂类 | 添加新产品需要添加新的工厂类 | 添加新产品族容易,添加新产品困难 |
| 使用场景 | 产品种类少,不需要频繁扩展 | 产品种类多,需要频繁扩展 | 需要创建一系列相关产品 |
使用场景
简单工厂使用场景
-
核心特点:一个工厂类封装所有产品的创建逻辑,客户端传入参数即可获取对应实例;优点是简单、减少重复代码,缺点是新增产品需修改工厂 (违反开闭原则);
-
封装通用请求 / API 调用 (最典型):前端项目中,不同接口的请求方式 (GET/POST)、参数格式、拦截逻辑可能不同,用简单工厂统一创建请求实例,避免重复写请求逻辑;// 抽象请求类(模拟) class Request { send() { throw new Error("需实现发送方法"); } } // 具体请求:GET请求 class GetRequest extends Request { constructor(url, params) { super(); this.url = url; this.params = params; } send() { return fetch(`${this.url}?${new URLSearchParams(this.params)}`, { method: "GET" }); } } // 具体请求:POST请求 class PostRequest extends Request { constructor(url, data) { super(); this.url = url; this.data = data; } send() { return fetch(this.url, { method: "POST", body: JSON.stringify(this.data), headers: { "Content-Type": "application/json" } }); } } // 简单工厂:请求工厂 class RequestFactory { static createRequest(type, url, data) { switch (type.toLowerCase()) { case "get": return new GetRequest(url, data); case "post": return new PostRequest(url, data); default: throw new Error(`不支持${type}请求`); } } } // 调用(客户端只需传类型,无需关心请求细节) const userRequest = RequestFactory.createRequest("get", "/api/user", { id: 1 }); userRequest.send().then(res => res.json()); -
弹窗 / 提示组件的创建(UI 组件场景):项目中常用的 Toast、Alert、Confirm 弹窗,逻辑相似但样式 / 交互不同,用简单工厂统一创建,减少页面重复代码;// 抽象弹窗类 class Modal { show() { throw new Error("需实现显示方法"); } } class Toast extends Modal { show() { console.log("轻提示:操作成功"); } } class Alert extends Modal { show() { console.log("警告弹窗:数据异常"); } } // 简单工厂:弹窗工厂 class ModalFactory { static createModal(type) { switch (type) { case "toast": return new Toast(); case "alert": return new Alert(); default: return new Toast(); // 默认返回轻提示 } } } // 页面调用 ModalFactory.createModal("toast").show();
工厂方法使用场景
-
核心特点:一个产品对应一个工厂,新增产品只需新增 「产品类 + 工厂类」,无需修改原有代码 (符合开闭原则);缺点是类数量会增加;
-
多渠道登录 / 支付集成(核心场景):项目需集成微信、支付宝、手机号等登录方式,每种登录的逻辑独立且可能后续新增 (如微博登录),用工厂方法解耦;// 抽象登录产品 class Login { login(credentials) { throw new Error("需实现登录方法"); } } // 具体产品:微信登录 class WxLogin extends Login { login(code) { return fetch("/api/login/wx", { method: "POST", body: JSON.stringify({ code }) }); } } // 具体产品:手机号登录 class PhoneLogin extends Login { login(phone, code) { return fetch("/api/login/phone", { method: "POST", body: JSON.stringify({ phone, code }) }); } } // 抽象工厂:登录工厂 class LoginFactory { createLogin() { throw new Error("需实现创建登录实例方法"); } } // 具体工厂:微信登录工厂 class WxLoginFactory extends LoginFactory { createLogin() { return new WxLogin(); } } // 具体工厂:手机号登录工厂 class PhoneLoginFactory extends LoginFactory { createLogin() { return new PhoneLogin(); } } // 调用(新增微博登录只需加 WbLogin + WbLoginFactory,无需改原有代码) const wxLoginFactory = new WxLoginFactory(); wxLoginFactory.createLogin().login("wx_code_123"); const phoneLoginFactory = new PhoneLoginFactory(); phoneLoginFactory.createLogin().login("13800138000", "123456"); -
多环境 API 适配(开发 / 测试 / 生产环境):不同环境的 API 基地址、拦截逻辑不同,且可能新增预发布环境,用工厂方法解耦;
抽象工厂使用场景
-
核心特点:一个工厂创建「一组相关 / 配套的产品」 (产品族),保证产品的一致性;缺点是新增产品种类需修改抽象工厂 (如新增「椅子」需改家具工厂);
-
主题系统(最典型:暗黑 / 浅色主题套件):项目的主题包含「按钮、输入框、表格」等组件样式,每种主题的组件样式是配套的,用抽象工厂保证主题统一;// 产品族1:按钮 class Button { render() { throw new Error("需实现渲染方法"); } } // 具体产品:浅色按钮 class LightButton extends Button { render() { return "<button style='background:#fff;'>浅色按钮</button>"; } } // 具体产品:暗黑按钮 class DarkButton extends Button { render() { return "<button style='background:#333;'>暗黑按钮</button>"; } } // 产品族2:输入框 class Input { render() { throw new Error("需实现渲染方法"); } } // 具体产品:浅色输入框 class LightInput extends Input { render() { return "<input style='border:1px solid #eee;'>"; } } // 具体产品:暗黑输入框 class DarkInput extends Input { render() { return "<input style='border:1px solid #666;'>"; } } // 抽象工厂:主题工厂(定义创建所有产品族的方法) class ThemeFactory { createButton() { throw new Error("需实现创建按钮方法"); } createInput() { throw new Error("需实现创建输入框方法"); } } // 具体工厂:浅色主题工厂(创建浅色套件) class LightThemeFactory extends ThemeFactory { createButton() { return new LightButton(); } createInput() { return new LightInput(); } } // 具体工厂:暗黑主题工厂(创建暗黑套件) class DarkThemeFactory extends ThemeFactory { createButton() { return new DarkButton(); } createInput() { return new DarkInput(); } } // 调用(切换主题只需换工厂,保证所有组件样式统一) const themeFactory = new DarkThemeFactory(); themeFactory.createButton().render(); // 暗黑按钮 themeFactory.createInput().render(); // 暗黑输入框 -
多端适配(PC / 移动端组件套件):PC 端和移动端的「导航栏、列表、弹窗」组件样式 / 交互不同,且是配套的,用抽象工厂创建对应端的组件套件;// 抽象工厂:端适配工厂 class DeviceFactory { createNav() {} // 创建导航 createList() {} // 创建列表 } // 具体工厂:PC 端工厂 class PcFactory extends DeviceFactory { createNav() { return new PcNav(); } createList() { return new PcList(); } } // 具体工厂:移动端工厂 class MobileFactory extends DeviceFactory { createNav() { return new MobileNav(); } createList() { return new MobileList(); } } -
国际化(i18n)文案套件:不同语言的「登录页文案、首页文案、个人中心文案」是配套的,用抽象工厂创建对应语言的文案套件;
三种工厂模式的核心选型思路
| 模式 | 核心适用场景 | 前端典型案例 | 选型关键 |
|---|---|---|---|
| 简单工厂 | 产品固定、轻量创建 | 请求封装、基础弹窗、格式化工具 | 产品类型少,不常新增 |
| 工厂方法 | 产品易扩展、单一产品创建 | 多渠道登录 / 支付、图表组件、多环境适配 | 产品类型可能新增,逻辑独立 |
| 抽象工厂 | 产品族创建、保证配套一致性 | 主题系统、多端适配、国际化文案 | 需创建一组配套产品 |
设计原则
上一篇