【C++设计模式】第二篇:工厂方法模式(Factory Method)
注意:复现代码时,确保 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)模式。
- 与依赖注入结合: 通过工厂实现依赖注入,提升代码可测试性。