【C++设计模式】第二篇:工厂方法模式(Factory Method)

发布于:2025-03-05 ⋅ 阅读:(22) ⋅ 点赞:(0)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

将对象创建延迟到子类,实现灵活扩展


1. 模式定义与用途

核心目标:定义一个创建对象的接口,但让子类决定实例化哪个类,实现解耦对象创建与使用。
常见场景:

  • 日志系统(支持多种日志格式:文件、网络、控制台)
  • 跨平台UI组件(不同操作系统下创建对应的按钮、窗口)
  • 游戏角色生成(根据玩家等级创建不同属性的敌人)

2. 模式结构解析

在这里插入图片描述

  • Product:定义对象的接口(如 ILogger)
  • ConcreteProduct:具体实现类(如 FileLogger, NetworkLogger)
  • Creator:声明工厂方法(如 createLogger())
  • ConcreteCreator:重写工厂方法,返回具体产品

3. 现代 C++ 实现示例:日志系统

3.1 基础实现

#include <iostream>
#include <memory>

// 产品接口
class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void log(const std::string& message) = 0;
};

// 具体产品:文件日志
class FileLogger : public ILogger {
public:
    void log(const std::string& message) override {
        std::cout << "Writing to file: " << message << std::endl;
    }
};

// 具体产品:网络日志
class NetworkLogger : public ILogger {
public:
    void log(const std::string& message) override {
        std::cout << "Sending over network: " << message << std::endl;
    }
};

// 创建者基类
class LoggerCreator {
public:
    virtual ~LoggerCreator() = default;
    virtual std::unique_ptr<ILogger> createLogger() = 0;

    void useLogger(const std::string& message) {
        auto logger = createLogger();
        logger->log(message);
    }
};

// 具体创建者:文件日志工厂
class FileLoggerCreator : public LoggerCreator {
public:
    std::unique_ptr<ILogger> createLogger() override {
        return std::make_unique<FileLogger>();
    }
};

// 具体创建者:网络日志工厂
class NetworkLoggerCreator : public LoggerCreator {
public:
    std::unique_ptr<ILogger> createLogger() override {
        return std::make_unique<NetworkLogger>();
    }
};

int main() {
    FileLoggerCreator fileFactory;
    fileFactory.useLogger("User login succeeded.");

    NetworkLoggerCreator networkFactory;
    networkFactory.useLogger("API request timed out.");

    return 0;
}

代码解析:

  • 通过 LoggerCreator 基类隔离客户端与具体日志类,新增日志类型只需添加 ConcreteCreator
  • 使用 std::unique_ptr 自动管理资源,避免内存泄漏。

3.2 支持运行时配置的增强实现

#include <map>
#include <functional>

// 日志类型枚举
enum class LoggerType { File, Network, Console };

// 全局工厂注册表(C++17 起支持 inline 静态成员初始化)
class LoggerFactory {
public:
    using CreatorFunc = std::function<std::unique_ptr<ILogger>()>;

    static void registerCreator(LoggerType type, CreatorFunc creator) {
        getRegistry()[type] = creator;
    }

    static std::unique_ptr<ILogger> create(LoggerType type) {
        auto it = getRegistry().find(type);
        if (it != getRegistry().end()) {
            return it->second();
        }
        throw std::invalid_argument("Unknown logger type");
    }

private:
    // 使用静态方法避免静态成员初始化顺序问题
    static std::map<LoggerType, CreatorFunc>& getRegistry() {
        static std::map<LoggerType, CreatorFunc> registry;
        return registry;
    }
};

// 注册具体创建函数(可在程序启动时调用)
void initLoggerFactory() {
    LoggerFactory::registerCreator(LoggerType::File, []() {
        return std::make_unique<FileLogger>();
    });
    LoggerFactory::registerCreator(LoggerType::Network, []() {
        return std::make_unique<NetworkLogger>();
    });
}

int main() {
    initLoggerFactory();
    auto fileLogger = LoggerFactory::create(LoggerType::File);
    fileLogger->log("System initialized.");

    return 0;
}

代码解析:

  • 通过注册表实现运行时动态扩展,无需修改已有代码即可添加新日志类型。
  • 结合 std::function 和 Lambda 表达式简化工厂方法绑定。

4. 应用场景示例:跨平台UI组件

// 产品接口:按钮
class IButton {
public:
    virtual void render() = 0;
    virtual ~IButton() = default;
};

// 具体产品:Windows 按钮
class WindowsButton : public IButton {
public:
    void render() override {
        std::cout << "Render a Windows-style button" << std::endl;
    }
};

// 具体产品:Linux 按钮
class LinuxButton : public IButton {
public:
    void render() override {
        std::cout << "Render a Linux-style button" << std::endl;
    }
};

// 创建者基类
class ButtonCreator {
public:
    virtual std::unique_ptr<IButton> createButton() = 0;
};

// 具体创建者
class WindowsButtonCreator : public ButtonCreator {
public:
    std::unique_ptr<IButton> createButton() override {
        return std::make_unique<WindowsButton>();
    }
};

class LinuxButtonCreator : public ButtonCreator {
public:
    std::unique_ptr<IButton> createButton() override {
        return std::make_unique<LinuxButton>();
    }
};

5. 工厂方法 vs 简单工厂 vs 抽象工厂

模式 核心区别
简单工厂 一个工厂类负责所有产品创建,违背开闭原则
工厂方法 每个产品对应一个工厂子类,支持扩展
抽象工厂 生产多个相关产品族(如整套UI组件)

6. 优缺点分析

优点 缺点
符合开闭原则,易于扩展新类型 类数量增加,代码结构复杂化
客户端与具体类解耦 需要预先设计工厂层次结构

7. 调试与扩展技巧

  • 验证多态行为: 在 VS2022 中设置断点,观察 createLogger() 返回的具体类型。
  • 性能优化: 对高频创建的对象,可结合对象池(Object Pool)模式。
  • 与依赖注入结合: 通过工厂实现依赖注入,提升代码可测试性。

模式结构解析网图备份

在这里插入图片描述