1. 工厂模式基础与核心价值
工厂模式是面向对象设计中应用最广泛的创建型模式之一,其核心在于将对象的实例化过程封装起来,使客户端代码与具体类解耦。在C++这种强类型语言中,工厂模式的价值尤为突出:
- 类型安全:通过静态类型检查避免运行时类型错误
- 扩展便利:新增产品类时无需修改客户端代码
- 逻辑集中:将复杂的对象创建条件判断集中管理
- 接口统一:所有产品遵循同一抽象接口
典型的简单工厂实现如下:
class Product { public: virtual void operation() = 0; virtual ~Product() = default; }; class ConcreteProductA : public Product { public: void operation() override { /*...*/ } }; class Factory { public: static std::unique_ptr<Product> createProduct(int type) { switch(type) { case 1: return std::make_unique<ConcreteProductA>(); // 其他产品类型... default: throw std::invalid_argument("Unknown product type"); } } };2. 工厂方法模式进阶实现
工厂方法模式通过引入抽象工厂类,进一步解耦了具体产品的创建过程。这种模式特别适合以下场景:
- 产品类具有层次结构
- 需要运行时动态决定创建哪种产品
- 不同环境下需要创建不同产品
一个标准的C++工厂方法实现示例:
// 抽象产品 class Document { public: virtual void open() = 0; virtual void save() = 0; virtual ~Document() = default; }; // 具体产品 class TextDocument : public Document { /*...*/ }; class SpreadsheetDocument : public Document { /*...*/ }; // 抽象工厂 class Application { public: virtual std::unique_ptr<Document> createDocument() = 0; void newDocument() { auto doc = createDocument(); doc->open(); // 添加到文档集合... } }; // 具体工厂 class TextApplication : public Application { public: std::unique_ptr<Document> createDocument() override { return std::make_unique<TextDocument>(); } };提示:在C++中实现工厂方法时,建议使用智能指针管理产品对象生命周期,避免内存泄漏。
3. 抽象工厂模式实战应用
抽象工厂模式用于创建相关或依赖对象的家族,而不需要明确指定具体类。在游戏开发、UI框架等场景中尤为常见:
// 抽象产品族 class Button { public: virtual void render() = 0; virtual ~Button() = default; }; class Checkbox { public: virtual void toggle() = 0; virtual ~Checkbox() = default; }; // 具体产品族 - Windows风格 class WinButton : public Button { /*...*/ }; class WinCheckbox : public Checkbox { /*...*/ }; // 抽象工厂 class GUIFactory { public: virtual std::unique_ptr<Button> createButton() = 0; virtual std::unique_ptr<Checkbox> createCheckbox() = 0; virtual ~GUIFactory() = default; }; // 具体工厂 class WinFactory : public GUIFactory { public: std::unique_ptr<Button> createButton() override { return std::make_unique<WinButton>(); } std::unique_ptr<Checkbox> createCheckbox() override { return std::make_unique<WinCheckbox>(); } };4. 模板工厂模式实现技巧
C++的模板特性可以实现更灵活的工厂模式,这种技术常用于库开发中:
template <typename ProductType> class GenericFactory { public: template <typename... Args> static std::unique_ptr<ProductType> create(Args&&... args) { return std::make_unique<ProductType>(std::forward<Args>(args)...); } }; // 使用示例 class CustomProduct { public: CustomProduct(int param1, double param2) { /*...*/ } }; auto product = GenericFactory<CustomProduct>::create(42, 3.14);这种实现方式的优势在于:
- 编译时类型检查
- 完美转发参数
- 无需修改工厂即可支持新产品类型
5. 原型模式与工厂的结合
原型模式通过克隆现有对象来创建新对象,与工厂模式结合可以产生强大的效果:
class Prototype { public: virtual std::unique_ptr<Prototype> clone() const = 0; virtual ~Prototype() = default; }; class ConcretePrototype : public Prototype { int data; public: std::unique_ptr<Prototype> clone() const override { return std::make_unique<ConcretePrototype>(*this); } }; class PrototypeFactory { std::unordered_map<int, std::unique_ptr<Prototype>> prototypes; public: void registerPrototype(int id, std::unique_ptr<Prototype> proto) { prototypes[id] = std::move(proto); } std::unique_ptr<Prototype> create(int id) const { auto it = prototypes.find(id); if (it != prototypes.end()) { return it->second->clone(); } throw std::invalid_argument("Unknown prototype ID"); } };6. 依赖注入框架中的工厂模式
现代C++依赖注入框架通常内置工厂模式的实现,例如:
class Service { public: virtual void execute() = 0; virtual ~Service() = default; }; class ServiceFactory { public: virtual std::unique_ptr<Service> create() = 0; virtual ~ServiceFactory() = default; }; class DIContainer { std::unordered_map<std::type_index, std::function<std::unique_ptr<void>()>> creators; public: template <typename T> void registerFactory(std::function<std::unique_ptr<T>()> factory) { creators[typeid(T)] = [factory]() -> std::unique_ptr<void> { return factory(); }; } template <typename T> std::unique_ptr<T> resolve() { auto it = creators.find(typeid(T)); if (it != creators.end()) { return std::unique_ptr<T>(static_cast<T*>(it->second().release())); } throw std::runtime_error("Service not registered"); } };7. 性能优化与线程安全考量
在实现工厂模式时,性能与线程安全是需要重点考虑的因素:
对象池技术:
template <typename T> class ObjectPool { std::queue<std::unique_ptr<T>> pool; std::mutex mtx; public: template <typename... Args> void preallocate(size_t count, Args&&... args) { std::lock_guard<std::mutex> lock(mtx); for (size_t i = 0; i < count; ++i) { pool.push(std::make_unique<T>(std::forward<Args>(args)...)); } } std::unique_ptr<T> acquire() { std::lock_guard<std::mutex> lock(mtx); if (pool.empty()) return nullptr; auto obj = std::move(pool.front()); pool.pop(); return obj; } void release(std::unique_ptr<T> obj) { std::lock_guard<std::mutex> lock(mtx); pool.push(std::move(obj)); } };线程安全工厂:
class ThreadSafeFactory { static std::mutex instanceMutex; static std::unique_ptr<ThreadSafeFactory> instance; ThreadSafeFactory() = default; public: ThreadSafeFactory(const ThreadSafeFactory&) = delete; ThreadSafeFactory& operator=(const ThreadSafeFactory&) = delete; static ThreadSafeFactory& getInstance() { std::lock_guard<std::mutex> lock(instanceMutex); if (!instance) { instance = std::make_unique<ThreadSafeFactory>(); } return *instance; } template <typename T, typename... Args> std::unique_ptr<T> create(Args&&... args) { return std::make_unique<T>(std::forward<Args>(args)...); } };8. 现代C++特性在工厂模式中的应用
C++17/20的新特性可以让工厂模式实现更加优雅:
使用std::variant实现类型安全工厂:
using ProductVariant = std::variant< std::unique_ptr<ConcreteProductA>, std::unique_ptr<ConcreteProductB> >; class ModernFactory { public: ProductVariant createProduct(int type) { switch(type) { case 1: return std::make_unique<ConcreteProductA>(); case 2: return std::make_unique<ConcreteProductB>(); default: throw std::invalid_argument("Unknown type"); } } };使用concept约束工厂产品类型:
template <typename T> concept ProductConcept = requires(T t) { { t.operation() } -> std::same_as<void>; }; template <ProductConcept T> class ConceptFactory { public: std::unique_ptr<T> create() { return std::make_unique<T>(); } };9. 工厂模式在Qt框架中的实践
Qt框架大量使用了工厂模式的思想,特别是在对象创建和元对象系统中:
// Qt风格的工厂方法示例 class QtProduct { public: virtual QString name() const = 0; virtual ~QtProduct() = default; }; class QtFactory { public: virtual QtProduct* create(QWidget* parent = nullptr) = 0; virtual ~QtFactory() = default; }; // 使用QMap注册工厂 class QtFactoryManager { QMap<QString, QtFactory*> factories; public: void registerFactory(const QString& id, QtFactory* factory) { factories[id] = factory; } QtProduct* create(const QString& id, QWidget* parent = nullptr) { if (factories.contains(id)) { return factories[id]->create(parent); } return nullptr; } };10. 设计模式组合应用案例
在实际项目中,工厂模式常与其他模式组合使用:
工厂+策略模式:
class CompressionStrategy { public: virtual void compress(const std::string& file) = 0; virtual ~CompressionStrategy() = default; }; class ZipStrategy : public CompressionStrategy { /*...*/ }; class RarStrategy : public CompressionStrategy { /*...*/ }; class CompressionFactory { public: static std::unique_ptr<CompressionStrategy> createStrategy(const std::string& type) { if (type == "zip") return std::make_unique<ZipStrategy>(); if (type == "rar") return std::make_unique<RarStrategy>(); throw std::invalid_argument("Unknown compression type"); } };工厂+装饰器模式:
class DataStream { public: virtual void write(const std::string& data) = 0; virtual ~DataStream() = default; }; class FileStream : public DataStream { /*...*/ }; class NetworkStream : public DataStream { /*...*/ }; class StreamDecorator : public DataStream { protected: std::unique_ptr<DataStream> wrapped; public: StreamDecorator(std::unique_ptr<DataStream> stream) : wrapped(std::move(stream)) {} }; class EncryptedStream : public StreamDecorator { /*...*/ }; class CompressedStream : public StreamDecorator { /*...*/ }; class StreamFactory { public: enum class StreamType { File, Network }; enum class DecoratorType { None, Encrypted, Compressed }; static std::unique_ptr<DataStream> createStream( StreamType type, DecoratorType decorator = DecoratorType::None ) { std::unique_ptr<DataStream> stream; switch(type) { case StreamType::File: stream = std::make_unique<FileStream>(); break; case StreamType::Network: stream = std::make_unique<NetworkStream>(); break; } switch(decorator) { case DecoratorType::Encrypted: return std::make_unique<EncryptedStream>(std::move(stream)); case DecoratorType::Compressed: return std::make_unique<CompressedStream>(std::move(stream)); default: return stream; } } };11. 工厂模式在游戏开发中的特殊应用
游戏引擎通常需要高效地创建大量游戏对象,这时工厂模式的变体显得尤为重要:
基于组件的对象工厂:
class GameObject { std::unordered_map<std::type_index, std::unique_ptr<void>> components; public: template <typename T, typename... Args> T& addComponent(Args&&... args) { auto ptr = std::make_unique<T>(std::forward<Args>(args)...); T& ref = *ptr; components[typeid(T)] = std::move(ptr); return ref; } template <typename T> T* getComponent() { auto it = components.find(typeid(T)); if (it != components.end()) { return static_cast<T*>(it->second.get()); } return nullptr; } }; class PrefabFactory { std::unordered_map<std::string, std::function<void(GameObject&)>> prefabs; public: void registerPrefab(const std::string& name, auto&& configurator) { prefabs[name] = std::forward<decltype(configurator)>(configurator); } GameObject create(const std::string& name) { GameObject obj; if (prefabs.count(name)) { prefabs[name](obj); } return obj; } };12. 工厂模式的最佳实践与反模式
在实际项目中使用工厂模式时,需要注意以下实践要点:
最佳实践:
- 优先使用智能指针管理对象生命周期
- 为工厂类定义清晰的接口契约
- 考虑使用依赖注入替代硬编码的工厂
- 对性能敏感的场景使用对象池技术
- 在多线程环境中确保工厂的线程安全
常见反模式:
- 上帝工厂:单个工厂类负责创建过多不同类型的对象
- 过度抽象:为简单对象创建引入不必要的工厂层次
- 循环依赖:工厂与产品之间存在双向依赖
- 忽略异常安全:工厂方法可能抛出异常导致资源泄漏
// 良好的工厂接口设计示例 class WellDesignedFactory { public: // 使用std::expected替代异常处理 std::expected<std::unique_ptr<Product>, ErrorCode> createProduct(ProductType type) { switch(type) { case ProductType::A: return std::make_unique<ProductA>(); case ProductType::B: return std::make_unique<ProductB>(); default: return std::unexpected(ErrorCode::InvalidType); } } // 支持批量创建 std::vector<std::unique_ptr<Product>> createProducts(std::span<const ProductType> types) { std::vector<std::unique_ptr<Product>> products; products.reserve(types.size()); for (auto type : types) { if (auto product = createProduct(type)) { products.push_back(std::move(*product)); } } return products; } };