c/c++ 工厂模式

 

工厂模式是一种创建对象的设计模式, 其核心思想是将对象的创建与使用分离, 从而提高代码的灵活性和可维护性

工厂模式主要有以下几种形式: 简单工厂、工厂方法、抽象工厂、模板工厂

分类

简单工厂模式

将对象创建逻辑集中在一个工厂类中, 扩展性较差, 增加新产品需要修改工厂类

classDiagram
    class SimpleFactory {
        +createProduct(type: string) Product*
    }
    class Product {
        <<interface>>
        +doUse() void
    }
    class ConcreteProductA {
        +doUse() void
    }
    class ConcreteProductB {
        +doUse() void
    }
    
    SimpleFactory ..> Product : creates
    ConcreteProductA ..|> Product
    ConcreteProductB ..|> Product

#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <functional>

// 1. 抽象产品
class Product {
public:
    virtual ~Product() = default;
    virtual void do_use() const = 0;
};

// 2. 具体产品 A
class ConcreteProductA : public Product {
public:
    void do_use() const override {
        std::cout << "Using ConcreteProductA\n";
    }
};

// 3. 具体产品 B
class ConcreteProductB : public Product {
public:
    void do_use() const override {
        std::cout << "Using ConcreteProductB\n";
    }
};

// 4. 简单工厂 (基于注册表)
class SimpleFactory {
public:
    // 注册表: 存储 类型标识 -> 创建函数 的映射
    using CreatorFunc = std::function<std::unique_ptr<Product>()>;
    
    // 注册新产品
    static void register_product(const std::string& type, CreatorFunc func) {
        registry()[type] = std::move(func);
    }

    // 创建产品
    static std::unique_ptr<Product> create(const std::string& type) {
        auto& reg = registry();
        auto it = reg.find(type);
        if (it != reg.end()) {
            return it->second();
        }
        throw std::runtime_error("Unknown product type: " + type);
    }

private:
    // 使用 Meyer's Singleton 确保注册表全局唯一且线程安全(C++11起)
    static std::unordered_map<std::string, CreatorFunc>& registry() {
        static std::unordered_map<std::string, CreatorFunc> instance;
        return instance;
    }
};

// 辅助宏: 用于在程序启动时自动注册产品(可选的高级技巧)
#define REGISTER_PRODUCT(type, class_name) \
    static bool class_name##_registered = []() { \
        SimpleFactory::register_product(type, []() { return std::make_unique<class_name>(); }); \
        return true; \
    }()

// 注册产品
REGISTER_PRODUCT("A", ConcreteProductA);
REGISTER_PRODUCT("B", ConcreteProductB);

int main() {
    // 客户端无需知道具体类, 只需通过标识符获取
    auto product_a = SimpleFactory::create("A");
    product_a->do_use();

    auto product_b = SimpleFactory::create("B");
    product_b->do_use();

    return 0;
}
  • 优点

客户端代码与具体产品类解耦;基于注册表的实现符合开闭原则, 新增产品只需注册, 无需修改工厂核心逻辑

  • 缺点

工厂类集中了所有产品的创建逻辑, 如果产品种类极多, 工厂类会变得非常庞大(“上帝类”)

工厂方法模式

为了解决简单工厂中”工厂类过于庞大”的问题, 工厂方法模式将具体的创建逻辑延迟到了子类

它定义了一个创建对象的接口, 但由子类决定实例化哪一个类

classDiagram
    class Creator {
        <<interface>>
        +factoryMethod() Product*
        +someOperation() void
    }
    class ConcreteCreatorA {
        +factoryMethod() Product*
    }
    class ConcreteCreatorB {
        +factoryMethod() Product*
    }
    class Product {
        <<interface>>
        +doUse() void
    }
    class ConcreteProductA {
        +doUse() void
    }
    class ConcreteProductB {
        +doUse() void
    }
    
    Creator <|-- ConcreteCreatorA
    Creator <|-- ConcreteCreatorB
    Product <|-- ConcreteProductA
    Product <|-- ConcreteProductB
    
    ConcreteCreatorA ..> ConcreteProductA : creates
    ConcreteCreatorB ..> ConcreteProductB : creates
    Creator --> Product : uses

#include <iostream>
#include <memory>

// 抽象产品
class Product {
public:
    virtual ~Product() = default;
    virtual void do_use() const = 0;
};

class ConcreteProductA : public Product {
public:
    void do_use() const override { std::cout << "Using Product A\n"; }
};

class ConcreteProductB : public Product {
public:
    void do_use() const override { std::cout << "Using Product B\n"; }
};

// 抽象工厂 (Creator)
class Creator {
public:
    virtual ~Creator() = default;
    // 工厂方法: 返回智能指针, 避免内存泄漏
    virtual std::unique_ptr<Product> factory_method() const = 0;
    
    // 业务逻辑: 使用工厂方法创建的产品
    void some_operation() const {
        auto product = factory_method();
        std::cout << "Creator doing operation with: ";
        product->do_use();
    }
};

// 具体工厂 A
class ConcreteCreatorA : public Creator {
public:
    std::unique_ptr<Product> factory_method() const override {
        return std::make_unique<ConcreteProductA>();
    }
};

// 具体工厂 B
class ConcreteCreatorB : public Creator {
public:
    std::unique_ptr<Product> factory_method() const override {
        return std::make_unique<ConcreteProductB>();
    }
};

int main() {
    // 客户端决定使用哪个具体工厂
    std::unique_ptr<Creator> creator = std::make_unique<ConcreteCreatorA>();
    creator->some_operation();

    creator = std::make_unique<ConcreteCreatorB>();
    creator->some_operation();

    return 0;
}
  • 优点

完全符合开闭原则, 新增产品时, 只需新增对应的具体产品类和具体工厂类, 无需修改现有代码

  • 缺点

每增加一个产品, 都要增加一个工厂类, 会导致系统中类的个数成对增加, 增加了系统的复杂度

抽象工厂模式

当系统需要创建一系列相关或相互依赖的对象(产品族) 时, 工厂方法模式就力不从心了

抽象工厂模式提供一个接口, 用于创建多个产品族中的相关对象, 而无需指定它们的具体类

📌 核心概念区分:

产品等级结构: 继承自同一个抽象产品的所有产品(如: 所有品牌的空调)

产品族: 由同一个工厂生产的, 属于不同产品等级结构的一组产品(如: 格力工厂生产的格力空调 + 格力电视)

classDiagram
    class AbstractFactory {
        <<interface>>
        +createProductA() ProductA*
        +createProductB() ProductB*
    }
    class ConcreteFactory1 {
        +createProductA() ProductA*
        +createProductB() ProductB*
    }
    class ConcreteFactory2 {
        +createProductA() ProductA*
        +createProductB() ProductB*
    }
    
    class AbstractProductA {
        <<interface>>
        +useA() void
    }
    class AbstractProductB {
        <<interface>>
        +useB() void
    }
    
    class ProductA1 {
        +useA() void
    }
    class ProductB1 {
        +useB() void
    }
    class ProductA2 {
        +useA() void
    }
    class ProductB2 {
        +useB() void
    }

    AbstractFactory <|-- ConcreteFactory1
    AbstractFactory <|-- ConcreteFactory2
    
    AbstractProductA <|-- ProductA1
    AbstractProductA <|-- ProductA2
    AbstractProductB <|-- ProductB1
    AbstractProductB <|-- ProductB2
    
    ConcreteFactory1 ..> ProductA1 : creates
    ConcreteFactory1 ..> ProductB1 : creates
    ConcreteFactory2 ..> ProductA2 : creates
    ConcreteFactory2 ..> ProductB2 : creates

#include <iostream>
#include <memory>

// ================= 产品等级结构 A: 按钮 =================
class Button {
public:
    virtual ~Button() = default;
    virtual void paint() const = 0;
};
class WinButton : public Button {
public:
    void paint() const override { std::cout << "Rendering Windows Button\n"; }
};
class MacButton : public Button {
public:
    void paint() const override { std::cout << "Rendering Mac Button\n"; }
};

// ================= 产品等级结构 B: 文本框 =================
class TextBox {
public:
    virtual ~TextBox() = default;
    virtual void paint() const = 0;
};
class WinTextBox : public TextBox {
public:
    void paint() const override { std::cout << "Rendering Windows TextBox\n"; }
};
class MacTextBox : public TextBox {
public:
    void paint() const override { std::cout << "Rendering Mac TextBox\n"; }
};

// ================= 抽象工厂 =================
class UIFactory {
public:
    virtual ~UIFactory() = default;
    virtual std::unique_ptr<Button> create_button() const = 0;
    virtual std::unique_ptr<TextBox> create_textbox() const = 0;
};

// ================= 具体工厂: Windows 产品族 =================
class WinUIFactory : public UIFactory {
public:
    std::unique_ptr<Button> create_button() const override {
        return std::make_unique<WinButton>();
    }
    std::unique_ptr<TextBox> create_textbox() const override {
        return std::make_unique<WinTextBox>();
    }
};

// ================= 具体工厂: Mac 产品族 =================
class MacUIFactory : public UIFactory {
public:
    std::unique_ptr<Button> create_button() const override {
        return std::make_unique<MacButton>();
    }
    std::unique_ptr<TextBox> create_textbox() const override {
        return std::make_unique<MacTextBox>();
    }
};

int main() {
    // 客户端只依赖抽象工厂, 保证创建出的产品族风格一致
    std::unique_ptr<UIFactory> factory = std::make_unique<MacUIFactory>();
    
    auto btn = factory->create_button();
    auto txt = factory->create_textbox();
    
    btn->paint(); // 输出 Mac 风格
    txt->paint(); // 输出 Mac 风格

    return 0;
}

模板工厂

在 C++ 中, 我们可以利用模板参数在编译期确定要创建的类型, 从而彻底消除运行时的类型判断开销(如 switch 或 dynamic_cast)

#include <iostream>
#include <memory>

class Product {
public:
    virtual ~Product() = default;
    virtual void do_use() const = 0;
};

class ProductA : public Product {
public:
    void do_use() const override { std::cout << "Using ProductA\n"; }
};

class ProductB : public Product {
public:
    void do_use() const override { std::cout << "Using ProductB\n"; }
};

// 模板工厂: 利用编译期多态
template <typename T>
class TemplateFactory {
public:
    // 约束: 确保 T 必须是 Product 的子类 (C++20 Concepts 语法, C++11 可用 static_assert)
    static std::unique_ptr<Product> create() {
        static_assert(std::is_base_of_v<Product, T>, "T must be derived from Product");
        return std::make_unique<T>();
    }
};

int main() {
    // 编译期确定类型, 无需运行时查表或 switch
    auto prod_a = TemplateFactory<ProductA>::create();
    auto prod_b = TemplateFactory<ProductB>::create();

    prod_a->do_use();
    prod_b->do_use();

    return 0;
}
  • 优点

极致的性能(编译期解析), 类型安全, 代码极其简洁

  • 缺点

无法在运行时动态决定创建哪种类型(因为模板参数必须在编译期确定), 它更适合于”已知所有可能类型, 且追求极致性能”的底层组件开发

对比

模式 特点 使用场景
简单工厂 集中管理对象创建 产品种类少、变化不频繁
工厂方法 子类决定创建对象 需要扩展新产品时
抽象工厂 创建一系列相关产品 多产品族、保证产品兼容性
模板工厂 通过模板生成任意产品 高扩展性、减少修改已有工厂代码

核心思想:

将对象创建与使用分离, 提高代码可维护性和灵活性

根据复杂度选择不同工厂模式: 简单工厂适合小项目, 抽象工厂适合产品族较多的复杂项目, 模板工厂适合追求高扩展性场景