C++工厂方法模式详解与应用实践
发布时间:2026/9/10 23:28:46 锦皓数字建站

1. 工厂方法模式概述工厂方法模式Factory Method Pattern是面向对象设计中最常用的创建型模式之一。在C开发中当我们需要创建对象但又不希望指定具体的类时工厂方法模式就派上了大用场。这个模式的核心思想是定义一个创建对象的接口但让子类决定实例化哪个类。工厂方法让类的实例化延迟到子类进行。想象一下汽车制造厂总部定义汽车的生产标准接口而各地的分厂子类决定具体生产什么型号的汽车。提示工厂方法模式特别适合以下场景当一个类无法预知它需要创建哪种类的对象或者当一个类希望由它的子类来指定它所创建的对象时。2. 模式结构与实现原理2.1 基本结构组件工厂方法模式通常包含以下几个关键组件抽象产品Product定义产品的接口是工厂方法创建的所有对象的父类具体产品ConcreteProduct实现抽象产品接口的具体类抽象工厂Creator声明工厂方法的核心接口具体工厂ConcreteCreator实现工厂方法返回具体产品实例2.2 C实现示例让我们通过一个简单的日志系统示例来理解工厂方法模式// 抽象产品日志记录器接口 class Logger { public: virtual ~Logger() {} virtual void log(const std::string message) 0; }; // 具体产品文件日志记录器 class FileLogger : public Logger { public: void log(const std::string message) override { // 实现文件日志记录逻辑 std::cout Logging to file: message std::endl; } }; // 具体产品控制台日志记录器 class ConsoleLogger : public Logger { public: void log(const std::string message) override { // 实现控制台日志记录逻辑 std::cout Logging to console: message std::endl; } }; // 抽象工厂 class LoggerFactory { public: virtual ~LoggerFactory() {} virtual Logger* createLogger() 0; }; // 具体工厂创建文件日志记录器 class FileLoggerFactory : public LoggerFactory { public: Logger* createLogger() override { return new FileLogger(); } }; // 具体工厂创建控制台日志记录器 class ConsoleLoggerFactory : public LoggerFactory { public: Logger* createLogger() override { return new ConsoleLogger(); } };2.3 模式工作原理当客户端代码需要使用日志记录器时它不需要直接实例化具体的日志类而是通过工厂来获取void clientCode(LoggerFactory factory) { Logger* logger factory.createLogger(); logger-log(This is a test message); delete logger; } int main() { FileLoggerFactory fileFactory; clientCode(fileFactory); // 使用文件日志 ConsoleLoggerFactory consoleFactory; clientCode(consoleFactory); // 使用控制台日志 return 0; }这种设计的关键优势在于客户端代码只依赖于抽象接口Logger和LoggerFactory而不需要知道具体的实现类。这使得系统更加灵活易于扩展。3. 工厂方法模式的高级应用3.1 参数化工厂方法有时候我们可能希望根据运行时参数来决定创建哪种产品。这时可以使用参数化的工厂方法class LoggerFactory { public: enum LoggerType { FILE, CONSOLE }; virtual ~LoggerFactory() {} virtual Logger* createLogger(LoggerType type) { switch(type) { case FILE: return new FileLogger(); case CONSOLE: return new ConsoleLogger(); default: throw std::invalid_argument(Invalid logger type); } } };3.2 使用模板实现工厂方法C的模板特性可以用来实现更灵活的工厂方法template typename T class GenericFactory { public: static T* create() { return new T(); } }; // 使用示例 auto fileLogger GenericFactoryFileLogger::create(); auto consoleLogger GenericFactoryConsoleLogger::create();3.3 单例工厂在某些场景下我们可能希望工厂本身是单例的class LoggerFactory { private: LoggerFactory() {} static LoggerFactory* instance; public: LoggerFactory(const LoggerFactory) delete; LoggerFactory operator(const LoggerFactory) delete; static LoggerFactory* getInstance() { if (!instance) { instance new LoggerFactory(); } return instance; } Logger* createLogger(LoggerType type) { // 实现同上 } }; LoggerFactory* LoggerFactory::instance nullptr;4. 工厂方法模式的优缺点分析4.1 主要优势松耦合客户端代码只需要知道抽象接口不需要了解具体实现类可扩展性添加新产品只需添加新的工厂类无需修改现有代码单一职责将产品创建逻辑集中在一个地方便于维护可测试性可以轻松替换为mock对象进行单元测试4.2 潜在缺点类数量增加每增加一个产品就需要增加一个具体工厂类抽象性增加代码变得更加抽象可能增加理解难度性能开销多了一层间接调用可能有轻微性能影响通常可忽略注意在性能敏感的嵌入式系统或实时系统中工厂方法模式带来的间接调用开销可能需要仔细评估。5. 实际应用场景与案例分析5.1 跨平台UI开发在开发跨平台UI框架时工厂方法模式非常有用。例如我们可以为每个平台Windows、Mac、Linux创建不同的按钮实现然后通过平台特定的工厂来创建// 抽象产品 class Button { public: virtual void render() 0; virtual void onClick() 0; }; // 具体产品 class WindowsButton : public Button { /*...*/ }; class MacButton : public Button { /*...*/ }; // 抽象工厂 class GUIFactory { public: virtual Button* createButton() 0; }; // 具体工厂 class WindowsFactory : public GUIFactory { public: Button* createButton() override { return new WindowsButton(); } }; class MacFactory : public GUIFactory { public: Button* createButton() override { return new MacButton(); } };5.2 游戏开发中的角色创建在游戏开发中工厂方法模式常用于创建不同类型的游戏角色class Character { public: virtual void attack() 0; }; class Warrior : public Character { /*...*/ }; class Mage : public Character { /*...*/ }; class CharacterFactory { public: virtual Character* createCharacter() 0; }; class WarriorFactory : public CharacterFactory { /*...*/ }; class MageFactory : public CharacterFactory { /*...*/ };5.3 数据库连接管理数据库连接池通常使用工厂方法模式来创建不同类型的数据库连接class DatabaseConnection { public: virtual void connect() 0; }; class MySQLConnection : public DatabaseConnection { /*...*/ }; class PostgreSQLConnection : public DatabaseConnection { /*...*/ }; class ConnectionFactory { public: virtual DatabaseConnection* createConnection() 0; };6. 工厂方法模式与其他设计模式的关系6.1 与抽象工厂模式的区别工厂方法模式关注的是单个产品的创建而抽象工厂模式关注的是产品家族的创建。工厂方法通过继承实现抽象工厂通过组合实现。6.2 与简单工厂的区别简单工厂把所有的创建逻辑放在一个类中而工厂方法将创建逻辑分散到各个子类中。简单工厂违背了开闭原则而工厂方法遵循了开闭原则。6.3 与模板方法模式的结合工厂方法模式常常与模板方法模式一起使用。模板方法定义算法的骨架而工厂方法用于创建算法中需要的对象。7. 性能优化与最佳实践7.1 对象池技术对于创建成本高的对象可以结合对象池技术class LoggerPool { private: std::vectorLogger* pool; LoggerFactory factory; public: LoggerPool(LoggerFactory f, size_t initialSize) : factory(f) { for (size_t i 0; i initialSize; i) { pool.push_back(factory.createLogger()); } } Logger* acquire() { if (pool.empty()) { return factory.createLogger(); } Logger* logger pool.back(); pool.pop_back(); return logger; } void release(Logger* logger) { pool.push_back(logger); } };7.2 使用智能指针管理资源在现代C中应该使用智能指针来管理工厂创建的对象std::unique_ptrLogger LoggerFactory::createLogger() { return std::make_uniqueFileLogger(); }7.3 线程安全考虑如果工厂可能被多个线程同时访问需要考虑线程安全class ThreadSafeLoggerFactory { std::mutex mtx; public: std::unique_ptrLogger createLogger() { std::lock_guardstd::mutex lock(mtx); return std::make_uniqueFileLogger(); } };8. 常见问题与解决方案8.1 循环依赖问题当产品和工厂相互引用时可能导致循环依赖。解决方案使用前向声明将工厂和产品分离到不同的头文件中使用接口隔离8.2 动态注册工厂有时我们希望能在运行时动态添加新的工厂class LoggerFactoryRegistry { std::mapstd::string, std::functionLogger*() factories; public: void registerFactory(const std::string name, std::functionLogger*() factory) { factories[name] factory; } Logger* createLogger(const std::string name) { auto it factories.find(name); if (it ! factories.end()) { return it-second(); } throw std::runtime_error(Unknown logger type); } };8.3 处理创建失败工厂方法可能需要处理创建失败的情况std::unique_ptrLogger SafeLoggerFactory::createLogger() { try { return std::make_uniqueFileLogger(); } catch (const std::exception e) { // 回退到基本日志 return std::make_uniqueBasicLogger(); } }9. 现代C中的改进实现9.1 使用std::function作为工厂using LoggerFactory std::functionstd::unique_ptrLogger(); LoggerFactory fileLoggerFactory []() { return std::make_uniqueFileLogger(); }; auto logger fileLoggerFactory();9.2 可变参数工厂template typename Product, typename... Args class VariadicFactory { public: static std::unique_ptrProduct create(Args... args) { return std::make_uniqueProduct(std::forwardArgs(args)...); } };9.3 结合CRTP实现静态多态template typename Derived class Factory { public: template typename... Args static auto create(Args... args) { return Derived::createImpl(std::forwardArgs(args)...); } }; class MyLoggerFactory : public FactoryMyLoggerFactory { friend class FactoryMyLoggerFactory; static std::unique_ptrLogger createImpl() { return std::make_uniqueFileLogger(); } };10. 测试策略与Mock对象工厂方法模式的一个巨大优势是便于测试。我们可以创建Mock工厂来生成测试用的Mock对象class MockLogger : public Logger { public: MOCK_METHOD(void, log, (const std::string), (override)); }; class MockLoggerFactory : public LoggerFactory { public: MOCK_METHOD(Logger*, createLogger, (), (override)); }; TEST(LoggerTest, TestLogging) { MockLoggerFactory factory; MockLogger logger; EXPECT_CALL(factory, createLogger()) .WillOnce(Return(logger)); EXPECT_CALL(logger, log(test message)); clientCode(factory); }11. 在大型项目中的实际应用经验在多年C开发中我发现工厂方法模式在以下场景特别有价值插件系统每个插件可以提供自己的工厂来创建特定功能的对象序列化/反序列化根据类型标识符创建相应的对象依赖注入通过工厂来控制对象的创建和生命周期一个实用的技巧是结合工厂方法和原型模式class PrototypeFactory { std::unordered_mapstd::string, std::unique_ptrPrototype prototypes; public: void registerPrototype(const std::string name, std::unique_ptrPrototype proto) { prototypes[name] std::move(proto); } std::unique_ptrPrototype create(const std::string name) { auto it prototypes.find(name); if (it ! prototypes.end()) { return it-second-clone(); } return nullptr; } };12. 设计模式组合应用案例让我们看一个结合工厂方法、策略模式和观察者模式的日志系统设计// 策略模式日志格式策略 class LogFormatter { public: virtual std::string format(const std::string message) 0; }; // 观察者模式日志事件通知 class LogObserver { public: virtual void onLog(const std::string message) 0; }; // 产品接口扩展 class AdvancedLogger : public Logger { public: virtual void addObserver(LogObserver* observer) 0; virtual void setFormatter(LogFormatter* formatter) 0; }; // 具体产品实现 class AdvancedFileLogger : public AdvancedLogger { std::vectorLogObserver* observers; LogFormatter* formatter; public: void log(const std::string message) override { std::string formatted formatter ? formatter-format(message) : message; // 写入文件 for (auto obs : observers) { obs-onLog(formatted); } } void addObserver(LogObserver* observer) override { observers.push_back(observer); } void setFormatter(LogFormatter* formatter) override { this-formatter formatter; } }; // 工厂接口扩展 class AdvancedLoggerFactory : public LoggerFactory { public: virtual AdvancedLogger* createAdvancedLogger() 0; };这种设计展示了如何将工厂方法模式与其他模式结合创建出更灵活、更强大的系统架构。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。