什么是工厂方法模式?

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义一个用于创建对象的接口(或抽象方法),但将具体对象的创建延迟到子类中。

与简单工厂模式不同,工厂方法模式不通过一个统一的工厂类创建所有对象,而是为每个产品类型对应一个具体工厂,由具体工厂负责创建对应的产品。这样,当新增产品时,无需修改现有工厂代码,只需新增产品类和对应的工厂类,更符合 “开闭原则”。

工厂方法模式的核心角色

  1. 抽象产品(Product):定义所有具体产品的公共接口(或父类)。
  2. 具体产品(ConcreteProduct):实现抽象产品接口的具体类。
  3. 抽象工厂(Factory):声明一个创建产品的抽象方法(工厂方法),返回抽象产品类型。
  4. 具体工厂(ConcreteFactory):实现抽象工厂的方法,创建并返回具体产品实例。

JavaScript 实现工厂方法模式示例:日志记录器

以下以 “日志记录器” 为例,实现工厂方法模式。需求是:支持控制台日志、文件日志两种记录方式,未来可能扩展数据库日志。通过工厂方法模式,每种日志类型对应一个具体工厂,客户端通过工厂获取日志实例。

代码实现 - javascript
// -------------- 1. 抽象产品:日志记录器基类 --------------
class Logger {
  // 抽象方法:记录日志
  log(message) {
    throw new Error("子类必须实现 log 方法");
  }
}

// -------------- 2. 具体产品:控制台日志、文件日志 --------------
// 控制台日志
class ConsoleLogger extends Logger {
  log(message) {
    console.log(`[Console] ${new Date().toLocaleString()}: ${message}`);
  }
}

// 文件日志(模拟,实际会写入文件)
class FileLogger extends Logger {
  log(message) {
    console.log(`[File] ${new Date().toLocaleString()}: ${message}(已写入日志文件)`);
  }
}

// -------------- 3. 抽象工厂:日志工厂接口 --------------
class LoggerFactory {
  // 抽象工厂方法:创建日志记录器
  createLogger() {
    throw new Error("子类必须实现 createLogger 方法");
  }
}

// -------------- 4. 具体工厂:控制台日志工厂、文件日志工厂 --------------
// 控制台日志工厂
class ConsoleLoggerFactory extends LoggerFactory {
  createLogger() {
    return new ConsoleLogger(); // 返回控制台日志实例
  }
}

// 文件日志工厂
class FileLoggerFactory extends LoggerFactory {
  createLogger() {
    return new FileLogger(); // 返回文件日志实例
  }
}

// -------------- 使用示例 --------------
// 客户端使用:通过具体工厂获取日志实例
function useLogger(loggerFactory) {
  const logger = loggerFactory.createLogger();
  logger.log("用户登录成功");
  logger.log("数据更新完成");
}

// 场景1:使用控制台日志
const consoleFactory = new ConsoleLoggerFactory();
useLogger(consoleFactory);
// 输出:
// [Console] 2025/11/14 10:00:00: 用户登录成功
// [Console] 2025/11/14 10:00:00: 数据更新完成

// 场景2:使用文件日志
const fileFactory = new FileLoggerFactory();
useLogger(fileFactory);
// 输出:
// [File] 2025/11/14 10:00:00: 用户登录成功(已写入日志文件)
// [File] 2025/11/14 10:00:00: 数据更新完成(已写入日志文件)

// -------------- 扩展:新增数据库日志(符合开闭原则) --------------
// 新增具体产品:数据库日志
class DatabaseLogger extends Logger {
  log(message) {
    console.log(`[Database] ${new Date().toLocaleString()}: ${message}(已存入数据库)`);
  }
}

// 新增具体工厂:数据库日志工厂
class DatabaseLoggerFactory extends LoggerFactory {
  createLogger() {
    return new DatabaseLogger();
  }
}

// 使用新日志类型,无需修改原有代码
const dbFactory = new DatabaseLoggerFactory();
useLogger(dbFactory);
// 输出:
// [Database] 2025/11/14 10:00:00: 用户登录成功(已存入数据库)

代码说明

  1. 抽象产品(Logger):定义了日志记录的通用接口 log,所有具体日志类都需实现该方法。
  2. 具体产品(ConsoleLogger、FileLogger 等):分别实现了控制台、文件、数据库的日志记录逻辑,专注于自身功能。
  3. 抽象工厂(LoggerFactory):声明了抽象工厂方法 createLogger,规定所有具体工厂必须实现该方法来创建日志实例。
  4. 具体工厂(ConsoleLoggerFactory 等):每个工厂对应一种日志类型,通过 createLogger 方法返回具体的日志实例。

工厂方法模式的优势

  • 符合开闭原则:新增产品时,只需新增对应的具体产品类和具体工厂类,无需修改现有代码(如示例中新增数据库日志)。
  • 单一职责:每个具体工厂只负责创建一种产品,逻辑清晰,易于维护。
  • 灵活性高:客户端可通过切换具体工厂来使用不同产品,无需关心产品的创建细节。

与简单工厂模式的区别

维度 简单工厂模式 工厂方法模式
工厂数量 一个统一的工厂类创建所有产品 每种产品对应一个具体工厂类
扩展方式 需修改工厂类的判断逻辑(违反开闭) 新增产品类和工厂类(符合开闭)
复杂度 实现简单,适合产品类型少的场景 结构稍复杂,适合产品类型多的场景

工厂方法模式更适合产品类型多变、需要频繁扩展的场景,是对简单工厂模式的进一步抽象和优化。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐