工厂模式核心概念解析

  1. 工厂模式 (Factory Pattern) 是一种创建型设计模式,核心思想是将对象的创建过程封装起来,用一个 “工厂” 类 / 函数来统一生产对象,而不是让调用方直接通过 new 关键字创建对象;
  2. 它解决的核心问题:
    1. 减少调用方与具体对象类的耦合 (调用方只需要告诉工厂 “要什么”,不用关心 “怎么造”)
    2. 统一管理对象的创建逻辑,便于后续扩展和维护;
    3. 隐藏对象创建的复杂细节 (比如初始化参数、依赖注入等)

工厂模式

三者的核心都是「把对象创建的逻辑封装起来」,区别仅在于「封装的粒度」:

  1. 简单工厂是「粗粒度」
  2. 工厂方法是「单产品粒度」
  3. 抽象工厂是「产品族粒度」

简单工厂模式(静态工厂)

  1. 最基础的实现,一个工厂函数根据传入的参数,直接创建并返回不同类型的对象 (不属于 GoF 23 种设计模式,但最常用)

  2. 类图:

  3. 场景选择:饮品店制作饮品,用户点单类型 (咖啡 / 奶茶) 直接创建对应的饮品,无需用户关心饮品的制作细节

    // 抽象饮品类(定义所有饮品的通用方法)
    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()); // 输出:制作奶茶:煮红茶 → 加鲜奶 → 调甜度 → 加珍珠 → 完成
    
  4. 场景解析:

    1. 顾客 (客户端) 只需要告诉饮品店 (工厂) 要「咖啡」或「奶茶」,无需自己动手制作;
    2. 如果新增饮品,需要修改 DrinkFactorycreateDrink 方法 (违反开闭原则),这也是简单工厂的核心缺点;

工厂方法模式

  1. 将对象的创建延迟到子类中,核心是 “定义创建对象的接口,让子类决定实例化哪个类”,每个产品对应一个工厂子类;

  2. 类图:

  3. 场景选择:电商平台的支付方式,每种支付方式对应一个专属工厂 (支付宝工厂 / 微信支付工厂),新增支付方式只需新增「支付类 + 工厂类」,无需修改原有代码;

    // 抽象产品:支付方式
    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 元:插卡 → 输入密码 → 支付成功
    
  4. 场景解析:

    1. 每种支付方式都有专属工厂,新增银联支付时,只需要新增 UnionPay (产品类)UnionPayFactory (工厂类),完全不改动原有代码;
    2. 客户端需要先选择「支付工厂」,再通过工厂获取「支付方式」,逻辑更清晰,扩展性更强;

抽象工厂模式

  1. 用于创建一系列相关 / 依赖的对象簇,而不用指定具体类;

  2. 类图:

  3. 实现代码:

    // 产品族 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()); // 输出:用欧式风格茶几:实木雕花桌面,雕花支架
    
  4. 场景解析:

    1. 抽象工厂解决的是「产品族」的问题:选择「现代工厂」就只能拿到现代沙发 + 现代茶几,不会出现「现代沙发配欧式茶几」的混搭情况,保证产品的一致性;
    2. 新增风格 (如中式风格) 只需新增「中式沙发 + 中式茶几 + 中式家具工厂」,无需修改原有代码;但如果新增家具类型 (如椅子),则需要修改抽象工厂和所有具体工厂 (这是抽象工厂的小缺点)

三种工厂模式的对比

特性 简单工厂 工厂方法 抽象工厂
目的 创建单一产品 创建单一产品,但延迟到子类 创建产品族
复杂度
灵活性
扩展性 添加新产品需要修改工厂类 添加新产品需要添加新的工厂类 添加新产品族容易,添加新产品困难
使用场景 产品种类少,不需要频繁扩展 产品种类多,需要频繁扩展 需要创建一系列相关产品

使用场景

简单工厂使用场景

  1. 核心特点:一个工厂类封装所有产品的创建逻辑,客户端传入参数即可获取对应实例;优点是简单、减少重复代码,缺点是新增产品需修改工厂 (违反开闭原则)

  2. 封装通用请求 / 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());
    
  3. 弹窗 / 提示组件的创建(UI 组件场景):项目中常用的 ToastAlertConfirm 弹窗,逻辑相似但样式 / 交互不同,用简单工厂统一创建,减少页面重复代码;

    // 抽象弹窗类
    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();
    

工厂方法使用场景

  1. 核心特点:一个产品对应一个工厂,新增产品只需新增 「产品类 + 工厂类」,无需修改原有代码 (符合开闭原则);缺点是类数量会增加;

  2. 多渠道登录 / 支付集成(核心场景):项目需集成微信、支付宝、手机号等登录方式,每种登录的逻辑独立且可能后续新增 (如微博登录),用工厂方法解耦;

    // 抽象登录产品
    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");
    
  3. 多环境 API 适配(开发 / 测试 / 生产环境):不同环境的 API 基地址、拦截逻辑不同,且可能新增预发布环境,用工厂方法解耦;

抽象工厂使用场景

  1. 核心特点:一个工厂创建「一组相关 / 配套的产品」 (产品族),保证产品的一致性;缺点是新增产品种类需修改抽象工厂 (如新增「椅子」需改家具工厂)

  2. 主题系统(最典型:暗黑 / 浅色主题套件):项目的主题包含「按钮、输入框、表格」等组件样式,每种主题的组件样式是配套的,用抽象工厂保证主题统一;

    // 产品族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(); // 暗黑输入框
    
  3. 多端适配(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(); }
    }
    
  4. 国际化(i18n)文案套件:不同语言的「登录页文案、首页文案、个人中心文案」是配套的,用抽象工厂创建对应语言的文案套件;

三种工厂模式的核心选型思路

模式 核心适用场景 前端典型案例 选型关键
简单工厂 产品固定、轻量创建 请求封装、基础弹窗、格式化工具 产品类型少,不常新增
工厂方法 产品易扩展、单一产品创建 多渠道登录 / 支付、图表组件、多环境适配 产品类型可能新增,逻辑独立
抽象工厂 产品族创建、保证配套一致性 主题系统、多端适配、国际化文案 需创建一组配套产品
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 工厂模式核心概念解析
  2. 2. 工厂模式
    1. 2.1. 简单工厂模式(静态工厂)
    2. 2.2. 工厂方法模式
    3. 2.3. 抽象工厂模式
    4. 2.4. 三种工厂模式的对比
  3. 3. 使用场景
    1. 3.1. 简单工厂使用场景
    2. 3.2. 工厂方法使用场景
    3. 3.3. 抽象工厂使用场景
    4. 3.4. 三种工厂模式的核心选型思路