在C++的面向对象设计中,工厂方法(Factory Method)模式是一种创建型模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而将实例化过程推迟到子类。虽然工厂方法的基本思想在各语言中都很相似,但在C++里,因其强类型系统、模板支持以及资源管理机制,工厂方法的实现细节与最佳实践值得深入探讨。
一、接口与抽象基类的定义
工厂方法首先需要一个抽象基类,用于声明产品对象的公共接口。例如:
class Product {
public:
virtual void use() = 0;
virtual ~Product() = default;
};
然后定义工厂抽象类,提供创建产品的方法:
class Factory {
public:
virtual std::unique_ptr <Product> create() = 0;
virtual ~Factory() = default;
};
这里使用 std::unique_ptr 是现代C++推荐的做法,它自动管理资源,避免了手动 delete 产生的内存泄漏风险。
二、具体工厂与产品实现
每个具体工厂实现 Factory::create 方法,返回对应的产品实例。
class ConcreteProductA : public Product {
public:
void use() override { std::cout << "使用产品A\n"; }
};
class ConcreteFactoryA : public Factory {
public:
std::unique_ptr <Product> create() override {
return std::make_unique <ConcreteProductA>();
}
};
同理可以实现 ConcreteProductB、ConcreteFactoryB 等。
三、工厂注册与运行时选择
在大型系统中,工厂往往需要动态注册,以支持插件式扩展。常见做法是使用静态全局映射:
using FactoryMaker = std::function<std::unique_ptr<Factory>()>;
std::unordered_map<std::string, FactoryMaker> registry;
template<typename F>
void registerFactory(const std::string& name) {
registry[name] = []() { return std::make_unique <F>(); };
}
然后在每个具体工厂实现文件中,调用 `registerFactory
(“A”)`。 运行时根据配置或命令行参数,获取相应工厂实例: “`cpp auto it = registry.find(“A”); if (it != registry.end()) { auto factory = it->second(); auto product = factory->create(); product->use(); } “` **四、线程安全与延迟初始化** 如果工厂注册在多线程环境下执行,需要确保映射的写操作是线程安全的。C++17 引入的 `std::call_once` 与 `std::once_flag` 可以用来实现一次性初始化: “`cpp std::once_flag flag; void initRegistry() { std::call_once(flag, [](){ registerFactory (“A”); registerFactory (“B”); }); } “` 在使用前调用 `initRegistry()`,即可保证注册过程只执行一次,避免竞态条件。 **五、与单例模式的混合** 有时工厂本身只需一个实例,可以将工厂类实现为单例。C++11 的局部静态变量天然线程安全,示例: “`cpp class SingletonFactory : public Factory { public: static SingletonFactory& instance() { static SingletonFactory inst; return inst; } std::unique_ptr create() override { /* … */ } private: SingletonFactory() = default; }; “` 需要注意的是,如果工厂依赖于外部资源或配置,单例可能导致资源竞争或初始化顺序问题,应根据实际情况决定是否采用单例。 **六、模板化工厂(泛型工厂)** 利用模板可以进一步简化工厂实现,尤其在创建简单、无状态的产品时: “`cpp template class SimpleFactory : public Factory { public: std::unique_ptr create() override { return std::make_unique (); } }; “` 随后注册: “`cpp registerFactory<simplefactory>(“A”); “` 模板化工厂消除了显式工厂类的冗余,提升代码可读性。 **七、异常安全与错误处理** 在工厂方法里,如果创建失败需要抛异常或返回空指针。采用 `std::unique_ptr` 可保证在异常抛出时不会泄漏已分配的资源。建议使用自定义异常类,携带错误信息: “`cpp class FactoryException : public std::runtime_error { public: FactoryException(const std::string& msg) : std::runtime_error(msg) {} }; “` 在注册或创建阶段若出现错误,直接抛出此异常,调用方可捕获并做相应处理。 **八、总结** 1. **使用 RAII**:工厂返回 `std::unique_ptr`,避免手动管理内存。 2. **注册机制**:采用全局映射与 `std::function`,支持插件化扩展。 3. **线程安全**:使用 `std::call_once` 或局部静态变量保证一次性初始化。 4. **模板化简化**:简单工厂可通过模板实现,减少样板代码。 5. **异常安全**:使用 `std::unique_ptr` 与自定义异常,确保资源不泄漏。 通过以上细节,C++中的工厂方法既保持了面向对象的设计优势,又充分利用了现代C++的语言特性,既安全又高效。</simplefactory