23种设计模式 - 工厂方法(Factory Method)

工厂方法模式(Factory Method)------ 你说要啥,我给你造

大白话解释

你去奶茶店点单,说"要一杯珍珠奶茶",店员就给你做一杯。你不需要知道怎么煮珍珠、怎么调茶、怎么打奶盖------你只管说"要什么",工厂负责"怎么造"

工厂方法模式:定义一个创建对象的接口,但让子类决定实例化哪个类。创建的细节交给子类,调用者只关心拿到的结果。

常见场景:

  • 日志系统(文件日志、数据库日志、控制台日志)
  • UI 组件(Windows 风格按钮、Mac 风格按钮)
  • 数据库驱动(MySQL、PostgreSQL、SQLite 连接器)

核心思路

  1. 定义产品接口(所有产品长啥样)
  2. 定义工厂接口(工厂该干什么)
  3. 具体产品类实现产品接口
  4. 具体工厂类实现工厂接口,负责创建对应产品

C++ 代码示例

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

// =====================
// 第一步:定义产品接口
// =====================
class Logger {
public:
    virtual ~Logger() = default;
    virtual void log(const std::string& message) = 0;
};

// =====================
// 第二步:具体产品
// =====================

// 控制台日志
class ConsoleLogger : public Logger {
public:
    void log(const std::string& message) override {
        std::cout << "[控制台] " << message << "\n";
    }
};

// 文件日志
class FileLogger : public Logger {
public:
    void log(const std::string& message) override {
        std::cout << "[文件] 写入 app.log: " << message << "\n";
        // 实际项目中这里会真正写文件
    }
};

// 数据库日志
class DatabaseLogger : public Logger {
public:
    void log(const std::string& message) override {
        std::cout << "[数据库] INSERT INTO logs: " << message << "\n";
    }
};

// =====================
// 第三步:定义工厂接口
// =====================
class LoggerFactory {
public:
    virtual ~LoggerFactory() = default;
    // 工厂方法:子类来实现具体创建逻辑
    virtual std::unique_ptr<Logger> createLogger() = 0;

    // 工厂可以包含通用业务逻辑
    void logWithTimestamp(const std::string& message) {
        auto logger = createLogger();
        logger->log("[2026-01-01 12:00:00] " + message);
    }
};

// =====================
// 第四步:具体工厂
// =====================
class ConsoleLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<ConsoleLogger>();
    }
};

class FileLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<FileLogger>();
    }
};

class DatabaseLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<DatabaseLogger>();
    }
};

// =====================
// 使用示例
// =====================
void doBusinessLogic(LoggerFactory& factory) {
    auto logger = factory.createLogger();
    logger->log("用户登录成功");
    logger->log("订单创建完毕");
}

int main() {
    std::cout << "=== 开发环境(控制台日志)===\n";
    ConsoleLoggerFactory consoleFactory;
    doBusinessLogic(consoleFactory);

    std::cout << "\n=== 生产环境(文件日志)===\n";
    FileLoggerFactory fileFactory;
    doBusinessLogic(fileFactory);

    std::cout << "\n=== 审计环境(数据库日志)===\n";
    DatabaseLoggerFactory dbFactory;
    doBusinessLogic(dbFactory);

    std::cout << "\n=== 带时间戳的日志 ===\n";
    consoleFactory.logWithTimestamp("系统启动完成");

    return 0;
}

输出:

plaintext 复制代码
=== 开发环境(控制台日志)===
[控制台] 用户登录成功
[控制台] 订单创建完毕

=== 生产环境(文件日志)===
[文件] 写入 app.log: 用户登录成功
[文件] 写入 app.log: 订单创建完毕

=== 审计环境(数据库日志)===
[数据库] INSERT INTO logs: 用户登录成功
[数据库] INSERT INTO logs: 订单创建完毕

=== 带时间戳的日志 ===
[控制台] [2026-01-01 12:00:00] 系统启动完成

和简单工厂的区别

简单工厂 工厂方法
结构 一个工厂 if-else 搞定一切 每种产品对应一个工厂子类
扩展 加新产品要改工厂代码 加新产品只需新增工厂子类
符合 ❌ 违反开闭原则 ✅ 符合开闭原则

优缺点

说明
✅ 优点 创建和使用分离,调用方不依赖具体类
✅ 优点 扩展新产品无需修改已有代码(开闭原则)
❌ 缺点 每增加一个产品就要增加一对产品类+工厂类
❌ 缺点 类的数量会膨胀
相关推荐
workflower17 分钟前
人形机器人全身运动控制能力大幅提升
人工智能·深度学习·机器学习·设计模式·机器人·自动化
折哥的程序人生 · 物流技术专研26 分钟前
Java 23 种设计模式:从踩坑到精通 | 备忘录模式 —— 快照与撤销,给对象装一个“后悔药”
java·设计模式·备忘录模式·行为型模式·java设计模式·从踩坑到精通·撤销重做
Kel32 分钟前
万物皆 Runnable:LangChain 如何用一个接口统一模型、链与图
人工智能·设计模式·架构
ttod_qzstudio4 小时前
【软考设计模式】策略模式:算法族的封装与动态切换精讲
设计模式·策略模式
咖啡八杯11 小时前
GoF设计模式——迭代器模式
java·后端·设计模式·迭代器模式
ttod_qzstudio13 小时前
【软考设计模式】外观模式:复杂子系统的“门面“封装与代码填空精讲
设计模式·外观模式
geovindu19 小时前
CSharp: Prototype Pattern
开发语言·后端·设计模式·.net·原型模式·创建型模式
ttod_qzstudio20 小时前
【软考设计模式】组合模式:“部分-整体“层次结构与树形对象统一操作精讲
设计模式·组合模式
ttod_qzstudio1 天前
【软考设计模式】装饰模式:“套娃“式增强与动态职责扩展精讲
设计模式·装饰模式
烬羽1 天前
MCP 多服务器架构实战:一个 Agent 同时操控地图、浏览器和文件
设计模式·设计