三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

C++工厂模式详解:从基础到高级应用

C++工厂模式详解:从基础到高级应用

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. 工厂模式的最佳实践与反模式

在实际项目中使用工厂模式时,需要注意以下实践要点:

最佳实践

  1. 优先使用智能指针管理对象生命周期
  2. 为工厂类定义清晰的接口契约
  3. 考虑使用依赖注入替代硬编码的工厂
  4. 对性能敏感的场景使用对象池技术
  5. 在多线程环境中确保工厂的线程安全

常见反模式

  1. 上帝工厂:单个工厂类负责创建过多不同类型的对象
  2. 过度抽象:为简单对象创建引入不必要的工厂层次
  3. 循环依赖:工厂与产品之间存在双向依赖
  4. 忽略异常安全:工厂方法可能抛出异常导致资源泄漏
// 良好的工厂接口设计示例 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; } };
← 返回列表