设计模式(C++)详解—工厂方法模式(2)

<摘要>

工厂方法模式就像一个万能玩具工厂,爸爸(抽象工厂)定义了制作玩具的标准流程,但让儿子们(具体工厂)决定具体生产哪种玩具。这种模式解决了"既要规范生产流程,又要灵活适应变化"的矛盾,通过将对象创建延迟到子类实现,让系统扩展像搭积木一样简单自然。本文将通过玩具工厂、披萨店和游戏武器三个生动故事,完整展示工厂方法模式在C++中的实现和应用。


<解析>

工厂方法模式:万能玩具工厂的故事

1. 背景故事:爸爸的玩具工厂

1.1 从前有个玩具大师

想象一下,有一位名叫老李的玩具大师,他开了家玩具工厂。最初,老李只生产一种玩具------木头小汽车。他的工厂是这样运作的:

cpp 复制代码
// 简单工厂模式 - 老李的初期工厂
class Toy {
public:
    virtual void play() = 0;
};

class WoodenCar : public Toy {
public:
    void play() override {
        std::cout << "嘟嘟!木头小汽车跑起来了!" << std::endl;
    }
};

class SimpleToyFactory {
public:
    static Toy* createToy(const std::string& type) {
        if (type == "car") {
            return new WoodenCar();
        }
        // 每增加一种新玩具,就要修改这里
        return nullptr;
    }
};

老李发现一个问题:每次他想生产新玩具(比如塑料机器人),都要亲自修改工厂的核心代码。这就像每次想做新菜都要重建厨房一样麻烦!

1.2 儿子的灵感

老李有三个儿子,各自擅长制作不同类型的玩具:

  • 大儿子擅长塑料玩具
  • 二儿子擅长电子玩具
  • 三儿子擅长毛绒玩具

老李想出了一个绝妙主意:"我不亲自做玩具了,我只制定做玩具的标准流程,让儿子们自己去决定具体做什么玩具!"

这就是工厂方法模式 的精髓:父亲定义框架,儿子实现细节

2. 核心概念:万能工厂的蓝图

2.1 工厂方法模式的童话解读

想象工厂方法模式就像一个乐高积木说明书

  1. 抽象产品(Toy):说明书上说"这里要放一个可以玩的部件"
  2. 具体产品(WoodenCar/PlasticRobot):实际拿到的积木块
  3. 抽象工厂(ToyFactory):说明书上的组装步骤
  4. 具体工厂(PlasticToyFactory):你按照说明书实际组装的过程

玩具大师 +制定标准() <<抽象>> 玩具工厂 +创建玩具() 大儿子工厂 +创建玩具() 二儿子工厂 +创建玩具() <<接口>> 玩具 +玩耍() 塑料玩具 电子玩具

2.2 三个关键角色

  1. 玩具大师(Client):想要玩具的孩子,不关心玩具怎么来的
  2. 工厂说明书(Creator):定义"如何生产玩具"的流程
  3. 具体工厂(Concrete Creator):实际动手生产的工匠

3. 设计意图:为什么需要万能工厂

3.1 现实世界的烦恼

假设你开了一家披萨店,最初只有一种披萨:

cpp 复制代码
// 糟糕的设计:直接创建具体对象
class Pizza {
public:
    virtual void prepare() = 0;
};

class CheesePizza : public Pizza {
public:
    void prepare() override {
        std::cout << "准备奶酪披萨..." << std::endl;
    }
};

// 在订单处理中直接创建
void orderPizza(const std::string& type) {
    Pizza* pizza = nullptr;
    
    if (type == "cheese") {
        pizza = new CheesePizza();
    }
    // 每增加一种披萨,就要修改这里
    
    pizza->prepare();
    delete pizza;
}

这样做的痛点:

  • 🚫 开闭原则 violation:增加新披萨要修改现有代码
  • 🚫 紧耦合:订单系统依赖具体披萨类
  • 🚫 难以测试:无法轻松模拟披萨对象

3.2 工厂方法模式的救赎

cpp 复制代码
// 抽象披萨工厂
class PizzaFactory {
public:
    virtual Pizza* createPizza() = 0;
    
    // 模板方法:定义标准制作流程
    void makePizza() {
        Pizza* pizza = createPizza();  // 工厂方法
        pizza->prepare();
        pizza->bake();
        pizza->cut();
        pizza->box();
        delete pizza;
    }
};

// 具体工厂
class CheesePizzaFactory : public PizzaFactory {
public:
    Pizza* createPizza() override {
        return new CheesePizza();
    }
};

class VeggiePizzaFactory : public PizzaFactory {
public:
    Pizza* createPizza() override {
        return new VeggiePizza();
    }
};

现在要增加新披萨,只需要"增加"而不是"修改":

cpp 复制代码
// 新增海鲜披萨:只需要扩展,不需要修改
class SeafoodPizza : public Pizza {
public:
    void prepare() override {
        std::cout << "准备新鲜海鲜披萨..." << std::endl;
    }
};

class SeafoodPizzaFactory : public PizzaFactory {
public:
    Pizza* createPizza() override {
        return new SeafoodPizza();
    }
};

4. 实例应用:三个生动故事

4.1 故事一:玩具王国的扩张

背景:老李的玩具工厂越来越成功,现在要生产三种玩具:塑料机器人、电子恐龙、毛绒泰迪熊。

实现

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

// 抽象产品:玩具
class Toy {
public:
    virtual ~Toy() {}
    virtual void play() = 0;
};

// 具体产品
class PlasticRobot : public Toy {
public:
    void play() override {
        std::cout << "🤖 塑料机器人:变身!发射激光!" << std::endl;
    }
};

class ElectronicDinosaur : public Toy {
public:
    void play() override {
        std::cout << "🦖 电子恐龙:发出震撼的咆哮声!" << std::endl;
    }
};

class TeddyBear : public Toy {
public:
    void play() override {
        std::cout << "🧸 毛绒泰迪:给你一个温暖的拥抱!" << std::endl;
    }
};

// 抽象工厂
class ToyFactory {
public:
    virtual ~ToyFactory() {}
    virtual std::unique_ptr<Toy> createToy() = 0;
    
    // 模板方法:标准生产流程
    void produceToy() {
        std::cout << "=== 开始生产玩具 ===" << std::endl;
        auto toy = createToy();
        toy->play();
        std::cout << "=== 玩具生产完成 ===\n" << std::endl;
    }
};

// 具体工厂
class RobotFactory : public ToyFactory {
public:
    std::unique_ptr<Toy> createToy() override {
        return std::make_unique<PlasticRobot>();
    }
};

class DinosaurFactory : public ToyFactory {
public:
    std::unique_ptr<Toy> createToy() override {
        return std::make_unique<ElectronicDinosaur>();
    }
};

class TeddyFactory : public ToyFactory {
public:
    std::unique_ptr<Toy> createToy() override {
        return std::make_unique<TeddyBear>();
    }
};

使用示例

cpp 复制代码
int main() {
    // 创建不同的玩具工厂
    RobotFactory robotFactory;
    DinosaurFactory dinoFactory;
    TeddyFactory teddyFactory;
    
    // 生产各种玩具
    std::cout << "🎪 欢迎来到万能玩具工厂!\n" << std::endl;
    
    robotFactory.produceToy();    // 生产机器人
    dinoFactory.produceToy();     // 生产恐龙
    teddyFactory.produceToy();    // 生产泰迪熊
    
    return 0;
}

输出结果

复制代码
🎪 欢迎来到万能玩具工厂!

=== 开始生产玩具 ===
🤖 塑料机器人:变身!发射激光!
=== 玩具生产完成 ===

=== 开始生产玩具 ===
🦖 电子恐龙:发出震撼的咆哮声!
=== 玩具生产完成 ===

=== 开始生产玩具 ===
🧸 毛绒泰迪:给你一个温暖的拥抱!
=== 玩具生产完成 ===

4.2 故事二:披萨店的数字化转型

背景:披萨店要支持线上订单,不同地区的店铺提供不同风味的披萨。

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>

// 抽象产品:披萨
class Pizza {
public:
    virtual ~Pizza() {}
    virtual void prepare() = 0;
    virtual void bake() {
        std::cout << "🔥 烘烤25分钟..." << std::endl;
    }
    virtual void cut() {
        std::cout << "🔪 切成8片..." << std::endl;
    }
    virtual void box() {
        std::cout << "📦 打包完成!" << std::endl;
    }
};

// 具体产品
class NewYorkCheesePizza : public Pizza {
public:
    void prepare() override {
        std::cout << "🍕 纽约风味奶酪披萨:薄脆饼底,额外奶酪" << std::endl;
    }
};

class ChicagoVeggiePizza : public Pizza {
public:
    void prepare() override {
        std::cout << "🍕 芝加哥风味素食披萨:厚实饼底,新鲜蔬菜" << std::endl;
    }
    void cut() override {
        std::cout << "🔪 切成方形片..." << std::endl;
    }
};

class CaliforniaSeafoodPizza : public Pizza {
public:
    void prepare() override {
        std::cout << "🍕 加州风味海鲜披萨:全麦饼底,新鲜海鲜" << std::endl;
    }
};

// 抽象工厂
class PizzaStore {
public:
    virtual ~PizzaStore() {}
    virtual std::unique_ptr<Pizza> createPizza(const std::string& type) = 0;
    
    std::unique_ptr<Pizza> orderPizza(const std::string& type) {
        std::cout << "\n👨‍🍳 接到订单:" << type << "披萨" << std::endl;
        auto pizza = createPizza(type);
        
        pizza->prepare();
        pizza->bake();
        pizza->cut();
        pizza->box();
        
        std::cout << "✅ 订单完成!\n" << std::endl;
        return pizza;
    }
};

// 具体工厂
class NewYorkPizzaStore : public PizzaStore {
public:
    std::unique_ptr<Pizza> createPizza(const std::string& type) override {
        if (type == "cheese") {
            return std::make_unique<NewYorkCheesePizza>();
        }
        throw std::runtime_error("不支持的披萨类型");
    }
};

class ChicagoPizzaStore : public PizzaStore {
public:
    std::unique_ptr<Pizza> createPizza(const std::string& type) override {
        if (type == "veggie") {
            return std::make_unique<ChicagoVeggiePizza>();
        }
        throw std::runtime_error("不支持的披萨类型");
    }
};

4.3 故事三:游戏武器工厂

背景:游戏中有不同种族,每个种族有独特的武器制造方式。

cpp 复制代码
#include <iostream>
#include <memory>
#include <vector>

// 抽象产品:武器
class Weapon {
public:
    virtual ~Weapon() {}
    virtual void attack() = 0;
    virtual std::string getName() = 0;
};

// 具体产品
class HumanSword : public Weapon {
public:
    void attack() override {
        std::cout << "⚔️ 长剑挥砍!造成20点伤害" << std::endl;
    }
    std::string getName() override { return "人类长剑"; }
};

class ElfBow : public Weapon {
public:
    void attack() override {
        std::cout << "🏹 精灵长弓射击!造成25点伤害" << std::endl;
    }
    std::string getName() override { return "精灵长弓"; }
};

class OrcAxe : public Weapon {
public:
    void attack() override {
        std::cout << "🪓 兽人战斧猛劈!造成30点伤害" << std::endl;
    }
    std::string getName() override { return "兽人战斧"; }
};

// 抽象工厂
class Blacksmith {
public:
    virtual ~Blacksmith() {}
    virtual std::unique_ptr<Weapon> forgeWeapon() = 0;
    
    void demonstrateWeapon() {
        auto weapon = forgeWeapon();
        std::cout << "打造完成:" << weapon->getName() << std::endl;
        weapon->attack();
    }
};

// 具体工厂
class HumanBlacksmith : public Blacksmith {
public:
    std::unique_ptr<Weapon> forgeWeapon() override {
        std::cout << "👨‍🏭 人类铁匠打造中..." << std::endl;
        return std::make_unique<HumanSword>();
    }
};

class ElfBlacksmith : public Blacksmith {
public:
    std::unique_ptr<Weapon> forgeWeapon() override {
        std::cout << "🧝‍♀️ 精灵工匠制作中..." << std::endl;
        return std::make_unique<ElfBow>();
    }
};

class OrcBlacksmith : public Blacksmith {
public:
    std::unique_ptr<Weapon> forgeWeapon() override {
        std::cout << "👹 兽人铁匠锻造中..." << std::endl;
        return std::make_unique<OrcAxe>();
    }
};

5. 交互流程:披萨订单的旅程

让我们用时序图展示一个披萨订单的完整生命周期:
顾客 纽约披萨店 披萨工厂 纽约奶酪披萨 订购奶酪披萨 createPizza("cheese") new NewYorkCheesePizza() 返回披萨对象 prepare() 准备完成 bake() 烘烤完成 cut() 切割完成 box() 打包完成 交付披萨 顾客 纽约披萨店 披萨工厂 纽约奶酪披萨

6. 最佳实践:智慧工厂的秘诀

6.1 使用智能指针管理资源

cpp 复制代码
// 好的实践:使用unique_ptr自动管理内存
class ModernToyFactory {
public:
    virtual std::unique_ptr<Toy> createToy() = 0;
    
    void produceToy() {
        auto toy = createToy();  // 自动内存管理
        toy->play();
        // 不需要手动delete,unique_ptr会自动处理
    }
};

6.2 工厂方法的参数化

cpp 复制代码
// 参数化工厂方法
class FlexiblePizzaStore : public PizzaStore {
public:
    std::unique_ptr<Pizza> createPizza(const std::string& type) override {
        if (type == "cheese") {
            return std::make_unique<NewYorkCheesePizza>();
        } else if (type == "veggie") {
            return std::make_unique<ChicagoVeggiePizza>();
        } else if (type == "seafood") {
            return std::make_unique<CaliforniaSeafoodPizza>();
        }
        throw std::runtime_error("未知的披萨类型: " + type);
    }
};

6.3 工厂方法的注册机制

cpp 复制代码
// 高级技巧:使用注册表动态管理工厂
class ToyFactoryRegistry {
private:
    std::map<std::string, std::function<std::unique_ptr<Toy>()>> factories;
    
public:
    void registerFactory(const std::string& name, 
                        std::function<std::unique_ptr<Toy>()> factory) {
        factories[name] = factory;
    }
    
    std::unique_ptr<Toy> createToy(const std::string& name) {
        if (factories.find(name) != factories.end()) {
            return factories[name]();
        }
        throw std::runtime_error("未知的玩具类型: " + name);
    }
};

// 使用注册机制
ToyFactoryRegistry registry;
registry.registerFactory("robot", []() { return std::make_unique<PlasticRobot>(); });
registry.registerFactory("dinosaur", []() { return std::make_unique<ElectronicDinosaur>(); });

auto toy = registry.createToy("robot");  // 创建机器人

7. 总结:工厂方法模式的智慧

工厂方法模式就像父亲教儿子做菜

  • 👨‍🍳 父亲(抽象工厂):提供菜谱和烹饪方法
  • 👦 儿子(具体工厂):根据菜谱实际做菜
  • 🍳 菜品(具体产品):最终的美味佳肴

核心优势

  • 开闭原则:增加新菜品不用修改父亲的菜谱
  • 解耦合:父亲不需要知道儿子具体怎么做菜
  • 可扩展:儿子可以自由创新,只要符合菜谱标准
  • 易测试:可以单独测试每个儿子的厨艺

适用场景

  • 🎮 游戏中的不同种族/职业拥有独特的生产方式
  • 🏪 电商平台的不同商户有不同的商品创建逻辑
  • 🌐 跨平台应用需要为不同操作系统创建UI组件
  • 🏭 制造业中不同生产线生产类似但不同的产品

通过这个生动的故事和实际代码示例,相信你已经深刻理解了工厂方法模式的精髓。记住:好的设计不是什么都自己做,而是定义好规则,让他人自由发挥!

相关推荐
深耕AI2 小时前
MFC 图形设备接口详解:小白从入门到掌握
c++·mfc
青草地溪水旁2 小时前
设计模式(C++)详解—工厂方法模式(1)
c++·工厂方法模式
·白小白2 小时前
C++类(上)默认构造和运算符重载
c++·学习
染指11103 小时前
11.ImGui-加载字体和中文
c++·windows·imgui
浩浩乎@4 小时前
【openGLES】纹理
c++·opengles
叫我龙翔4 小时前
【设计模式】从游戏角度开始了解设计模式 --- 抽象工厂模式
c++·游戏·设计模式
青草地溪水旁4 小时前
设计模式(C++)详解—单例模式(1)
c++·单例模式
HMBBLOVEPDX5 小时前
C++(深拷贝和浅拷贝)
开发语言·c++·浅拷贝和深拷贝
UrSpecial6 小时前
Linux线程
linux·开发语言·c++