【C++/Qt 进阶】设计模式系列(2):工厂模式——从游戏角色到披萨店

系列文章:

  1. 单例模式:【C++/Qt 进阶】设计模式系列(1):单例模式------饿汉式内存泄漏真相、指针单例存在的意义、五种实现终极对比-CSDN博客
  2. 工厂模式与抽象工厂模式(本篇)
  3. 建造者模式
  4. 原型模式
  5. 适配器模式
  6. 桥接模式(持续更新中)

前言

还记得初次接触工厂模式时,各种"产品""具体工厂""抽象产品"等专业术语让我一头雾水。直到我通过游戏角色创建 和披萨店运营这两个生活化案例来理解,才真正掌握其精髓。

本文将通过通俗易懂的讲解和完整的C++代码示例,系统讲解简单工厂、工厂方法和抽象工厂三种设计模式。


一、为什么需要工厂模式?

传统创建方式的痛点

假设你在开发一款RPG游戏,需要创建不同角色:

cpp 复制代码
// 游戏主流程中分散的创建代码
int main() {
    // 玩家选择战士
    Warrior* player = new Warrior();
    player->attack();
// 任务NPC创建法师
Mage* npc = new Mage();
npc->castSpell();

// Boss战创建弓箭手
Archer* boss = new Archer();
boss->shoot();

// 维护痛点:
// 1. 删除战士职业需要修改所有new Warrior()的地方
// 2. 新增职业需要修改多处创建逻辑
return 0;
}

主要问题:

  1. 创建逻辑分散,维护困难
  2. 客户端与具体类高度耦合
  3. 违反开闭原则(扩展需修改现有代码)

工厂模式的核心价值:封装对象创建过程,让客户端只需关注"使用什么",而不用关心"如何创建"。


二、简单工厂模式:角色创建中心

2.1 生活案例:餐厅点餐

在餐厅点餐时,你只需告诉服务员"要一份芝士披萨",服务员会向后厨下单。你不需要知道披萨的具体做法和厨师是谁。这里的服务员就是简单工厂。

2.2 游戏实现:统一角色创建

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
// =============== 角色基类 ===============
class Character {
public:
virtual ~Character() = default;
virtual void attack() = 0;
virtual std::string getClassName() = 0;
};
// =============== 具体角色 ===============
class Warrior : public Character {
public:
void attack() override {
std::cout << "⚔️ 战士:旋风斩!造成150点伤害\n";
}
std::string getClassName() override { return "战士"; }
};
class Mage : public Character {
public:
void attack() override {
std::cout << "🔥 法师:火球术!造成200点魔法伤害\n";
}
std::string getClassName() override { return "法师"; }
};
class Archer : public Character {
public:
void attack() override {
std::cout << "🏹 弓箭手:三重射击!造成120点伤害\n";
}
std::string getClassName() override { return "弓箭手"; }
};
// =============== 简单工厂 ===============
class SimpleCharacterFactory {
public:
static std::unique_ptr<Character> createCharacter(const std::string& type) {
if (type == "warrior") return std::make_unique<Warrior>();
if (type == "mage") return std::make_unique<Mage>();
if (type == "archer") return std::make_unique<Archer>();
throw std::invalid_argument("无效职业:" + type);
}
};
// =============== 使用示例 ===============
int main() {
std::cout << "======== 简单工厂模式演示 ========\n\n";
// 创建战士角色
auto player = SimpleCharacterFactory::createCharacter("warrior");
std::cout &lt;&lt; "创建职业:" &lt;&lt; player-&gt;getClassName() &lt;&lt; "\n";
player-&gt;attack();

// 创建法师NPC
auto npc = SimpleCharacterFactory::createCharacter("mage");
std::cout &lt;&lt; "创建职业:" &lt;&lt; npc-&gt;getClassName() &lt;&lt; "\n";
npc-&gt;attack();

return 0;
}

输出结果:

复制代码
======== 简单工厂模式演示 ========
创建职业:战士
⚔️ 战士:旋风斩!造成150点伤害
创建职业:法师
🔥 法师:火球术!造成200点魔法伤害

2.3 披萨店实现

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
// =============== 披萨基类 ===============
class Pizza {
public:
virtual ~Pizza() = default;
virtual void prepare() = 0;
virtual void bake() { std::cout << "烘烤15分钟\n"; }
virtual void box() { std::cout << "装盒完成\n"; }
};
// =============== 具体披萨 ===============
class CheesePizza : public Pizza {
public:
void prepare() override {
std::cout << "🧀 芝士披萨:加入马苏里拉芝士、番茄酱\n";
}
};
class PepperoniPizza : public Pizza {
public:
void prepare() override {
std::cout << "🍖 腊肠披萨:加入意式辣味腊肠、芝士\n";
}
};
// =============== 简单工厂 ===============
class SimplePizzaFactory {
public:
static std::unique_ptr<Pizza> createPizza(const std::string& type) {
if (type == "cheese") return std::make_unique<CheesePizza>();
if (type == "pepperoni") return std::make_unique<PepperoniPizza>();
throw std::invalid_argument("无此披萨类型");
}
};
// =============== 披萨店 ===============
class PizzaStore {
public:
void orderPizza(const std::string& type) {
auto pizza = SimplePizzaFactory::createPizza(type);
std::cout << "\n制作" << type << "披萨:\n";
pizza->prepare();
pizza->bake();
pizza->box();
}
};
int main() {
PizzaStore store;
store.orderPizza("cheese");
store.orderPizza("pepperoni");
return 0;
}

2.4 模式总结

优势:

  • 实现简单,集中管理创建逻辑
  • 客户端只需传入参数,无需了解创建细节

局限:

  • 新增产品类型需要修改工厂类
  • 产品类型多时工厂类会臃肿

适用场景:产品类型较少且稳定的简单项目


三、工厂方法模式:专业化创建

3.1 生活案例:连锁披萨店

假设你经营全国连锁披萨店,纽约分店制作薄底披萨,芝加哥分店制作深盘披萨。总部制定"准备→烘烤→装盒"的标准流程,但各分店自行实现具体制作方法。

3.2 游戏实现:职业训练营

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
// =============== 角色基类 ===============
class Character {
public:
virtual ~Character() = default;
virtual void attack() = 0;
virtual std::string getClassName() = 0;
};
class Warrior : public Character {
public:
void attack() override {
std::cout << "⚔️ 战士:英勇打击!\n";
}
std::string getClassName() override { return "战士"; }
};
cpp 复制代码
class Archer : public Character {
public:
    void attack() override {
        std::cout << "🏹 弓箭手:箭雨!\n";
    }
    std::string getClassName() override { return "弓箭手"; }
};
// ==================== 抽象工厂(训练营) ====================
class CharacterFactory {
public:
virtual ~CharacterFactory() = default;
// 工厂方法:由子类实现具体角色创建
virtual std::unique_ptr&lt;Character&gt; createCharacter() = 0;

// 模板方法:定义标准训练流程
void trainCharacter() {
    auto character = createCharacter();
    std::cout &lt;&lt; "训练" &lt;&lt; character-&gt;getClassName() &lt;&lt; "完成!\n";
    character-&gt;attack();
    std::cout &lt;&lt; "-------------------\n";
}
};
// ==================== 具体工厂(职业训练营) ====================
class WarriorFactory : public CharacterFactory {
public:
std::unique_ptr<Character> createCharacter() override {
return std::make_unique<Warrior>();
}
};
class MageFactory : public CharacterFactory {
public:
std::unique_ptr<Character> createCharacter() override {
return std::make_unique<Mage>();
}
};
class ArcherFactory : public CharacterFactory {
public:
std::unique_ptr<Character> createCharacter() override {
return std::make_unique<Archer>();
}
};
// ==================== 使用示例 ====================
int main() {
std::cout << "========== 工厂方法模式演示 ==========\n\n";
// 初始化各职业训练营
WarriorFactory warriorCamp;
MageFactory mageCamp;
ArcherFactory archerCamp;

// 执行训练流程
warriorCamp.trainCharacter();
mageCamp.trainCharacter();
archerCamp.trainCharacter();

// 扩展说明:只需添加新工厂类即可支持新职业
// 示例:class PriestFactory : public CharacterFactory { ... };

return 0;
}

运行结果:

复制代码
========== 工厂方法模式演示 ==========
训练战士完成!
⚔️ 战士:英勇打击!
训练法师完成!
🔥 法师:暴风雪!
训练弓箭手完成!
🏹 弓箭手:箭雨!

3.3 披萨店实现

cpp 复制代码
#include <iostream>
#include <memory>
// ==================== 披萨基类 ====================
class Pizza {
public:
virtual ~Pizza() = default;
virtual void prepare() = 0;
virtual void bake() = 0;
virtual void box() { std::cout << "装盒\n"; }
};
// ==================== 纽约风味披萨 ====================
class NYStyleCheesePizza : public Pizza {
public:
void prepare() override {
std::cout << "🗽 纽约芝士披萨:薄底、新鲜马苏里拉\n";
}
void bake() override {
std::cout << "砖炉高温快烤10分钟\n";
}
};
// ==================== 芝加哥风味披萨 ====================
class ChicagoStyleCheesePizza : public Pizza {
public:
void prepare() override {
std::cout << "🌬️ 芝加哥深盘芝士披萨:厚底、大量芝士\n";
}
void bake() override {
std::cout << "深烤盘慢烤45分钟\n";
}
};
// ==================== 抽象披萨店 ====================
class PizzaStore {
public:
virtual ~PizzaStore() = default;
// 标准制作流程(模板方法)
void orderPizza() {
    auto pizza = createPizza();
    std::cout &lt;&lt; "\n=== " &lt;&lt; getStoreName() &lt;&lt; " ===\n";
    pizza-&gt;prepare();
    pizza-&gt;bake();
    pizza-&gt;box();
    std::cout &lt;&lt; "请享用!\n";
}
protected:
// 工厂方法:由子类实现具体披萨类型
virtual std::unique_ptr<Pizza> createPizza() = 0;
virtual std::string getStoreName() = 0;
};
// ==================== 纽约分店 ====================
class NYPizzaStore : public PizzaStore {
protected:
std::unique_ptr<Pizza> createPizza() override {
return std::make_unique<NYStyleCheesePizza>();
}
std::string getStoreName() override {
return "纽约曼哈顿店";
}
};
// ==================== 芝加哥分店 ====================
class ChicagoPizzaStore : public PizzaStore {
protected:
std::unique_ptr<Pizza> createPizza() override {
return std::make_unique<ChicagoStyleCheesePizza>();
}
std::string getStoreName() override {
return "芝加哥深盘总店";
}
};
int main() {
NYPizzaStore nyStore;
ChicagoPizzaStore chicagoStore;
nyStore.orderPizza();
chicagoStore.orderPizza();

return 0;
}

3.4 工厂方法模式总结

核心思想:将对象创建委托给子类,由子类决定实例化哪个具体类。

优点:

  • 符合开闭原则,便于扩展新产品
  • 客户端仅依赖抽象接口

缺点:

  • 每个产品需对应一个工厂类,增加系统复杂度

适用场景:需要灵活扩展产品类型的系统


四、抽象工厂模式:装备套装系统

4.1 生活类比:统一供应链

经营高端披萨连锁时,需确保:

  • 意大利分店使用全套意式原料
  • 有机分店使用全套有机食材
  • 禁止跨系列原料混用

4.2 游戏实现:套装装备

cpp 复制代码
#include <iostream>
#include <memory>
#include <string>
// ==================== 抽象武器 ====================
class Weapon {
public:
virtual ~Weapon() = default;
virtual void use() = 0;
};
// 具体武器
class Sword : public Weapon {
public:
void use() override { std::cout << "🗡️ 挥动长剑\n"; }
};
class Staff : public Weapon {
public:
void use() override { std::cout << "🪄 挥舞法杖\n"; }
};
class Bow : public Weapon {
public:
void use() override { std::cout << "🏹 拉弓射箭\n"; }
};
// ==================== 抽象防具 ====================
class Armor {
public:
virtual ~Armor() = default;
virtual void equip() = 0;
};
// 具体防具
class HeavyArmor : public Armor {
public:
cpp 复制代码
class Robe : public Armor {
public:
    void equip() override { std::cout << "👘 装备法袍,魔力+50\n"; }
};
class LeatherArmor : public Armor {
public:
void equip() override { std::cout << "🧥 装备皮甲,敏捷+50\n"; }
};
// 装备套装抽象工厂
class EquipmentFactory {
public:
virtual ~EquipmentFactory() = default;
virtual std::unique_ptr<Weapon> createWeapon() = 0;
virtual std::unique_ptr<Armor> createArmor() = 0;
};
// 战士装备工厂
class WarriorEquipmentFactory : public EquipmentFactory {
public:
std::unique_ptr<Weapon> createWeapon() override {
return std::make_unique<Sword>();
}
std::unique_ptr<Armor> createArmor() override {
return std::make_unique<HeavyArmor>();
}
};
// 法师装备工厂
class MageEquipmentFactory : public EquipmentFactory {
public:
std::unique_ptr<Weapon> createWeapon() override {
return std::make_unique<Staff>();
}
std::unique_ptr<Armor> createArmor() override {
return std::make_unique<Robe>();
}
};
// 弓箭手装备工厂
class ArcherEquipmentFactory : public EquipmentFactory {
public:
std::unique_ptr<Weapon> createWeapon() override {
return std::make_unique<Bow>();
}
std::unique_ptr<Armor> createArmor() override {
return std::make_unique<LeatherArmor>();
}
};
// 使用装备工厂的角色类
class GameCharacter {
private:
std::unique_ptr<Weapon> weapon;
std::unique_ptr<Armor> armor;
std::string name;
public:
GameCharacter(const std::string& name,
std::unique_ptr<EquipmentFactory> factory)
: name(name) {
weapon = factory->createWeapon();
armor = factory->createArmor();
}
void showEquipment() {
    std::cout &lt;&lt; "\n角色:" &lt;&lt; name &lt;&lt; "\n";
    std::cout &lt;&lt; "装备检查:\n";
    weapon-&gt;use();
    armor-&gt;equip();
    std::cout &lt;&lt; "--- 装备成套,属性匹配 ✅ ---\n";
}
};
int main() {
std::cout << "========== 抽象工厂模式演示 ==========\n";
// 创建战士角色
GameCharacter warrior("亚瑟", 
    std::make_unique&lt;WarriorEquipmentFactory&gt;());
warrior.showEquipment();

// 创建法师角色
GameCharacter mage("甘道夫", 
    std::make_unique&lt;MageEquipmentFactory&gt;());
mage.showEquipment();

// 创建弓箭手角色
GameCharacter archer("莱戈拉斯", 
    std::make_unique&lt;ArcherEquipmentFactory&gt;());
archer.showEquipment();

return 0;
}

运行结果:

复制代码
========== 抽象工厂模式演示 ==========
角色:亚瑟
装备检查:
🗡️ 挥动长剑
🛡️ 装备重甲,防御+50
--- 装备成套,属性匹配 ✅ ---
角色:甘道夫
装备检查:
🪄 挥舞法杖
👘 装备法袍,魔力+50
--- 装备成套,属性匹配 ✅ ---
角色:莱戈拉斯
装备检查:
🏹 拉弓射箭
🧥 装备皮甲,敏捷+50
--- 装备成套,属性匹配 ✅ ---

4.3 披萨店原料供应链实现

cpp 复制代码
#include <iostream>
#include <memory>
// 抽象原料工厂
class IngredientFactory {
public:
virtual ~IngredientFactory() = default;
virtual std::string createDough() = 0;
virtual std::string createSauce() = 0;
virtual std::string createCheese() = 0;
};
// 意大利原料工厂
class ItalianIngredientFactory : public IngredientFactory {
public:
std::string createDough() override { return "意大利00号面粉"; }
std::string createSauce() override { return "圣马扎诺番茄酱"; }
std::string createCheese() override { return "帕尔马芝士"; }
};
// 有机原料工厂
class OrganicIngredientFactory : public IngredientFactory {
public:
std::string createDough() override { return "有机全麦面粉"; }
std::string createSauce() override { return "有机番茄酱"; }
std::string createCheese() override { return "有机马苏里拉"; }
};
// 披萨类
class Pizza {
private:
std::unique_ptr<IngredientFactory> factory;
public:
Pizza(std::unique_ptr<IngredientFactory> f)
: factory(std::move(f)) {}
void prepare() {
    std::cout &lt;&lt; "制作披萨:\n";
    std::cout &lt;&lt; "  面团:" &lt;&lt; factory-&gt;createDough() &lt;&lt; "\n";
    std::cout &lt;&lt; "  酱料:" &lt;&lt; factory-&gt;createSauce() &lt;&lt; "\n";
    std::cout &lt;&lt; "  芝士:" &lt;&lt; factory-&gt;createCheese() &lt;&lt; "\n";
    std::cout &lt;&lt; "所有原料来自同一产地 ✅\n";
}
};
int main() {
std::cout << "=== 意大利风情店 ===\n";
Pizza italianPizza(std::make_unique<ItalianIngredientFactory>());
italianPizza.prepare();
std::cout &lt;&lt; "\n=== 有机健康店 ===\n";
Pizza organicPizza(std::make_unique&lt;OrganicIngredientFactory&gt;());
organicPizza.prepare();

return 0;
}

4.4 抽象工厂模式总结

核心思想:创建相关对象系列,确保产品兼容性。

优点:

  • 保证产品族一致性
  • 客户端与具体产品解耦

缺点:

  • 扩展新产品需修改接口

适用场景:需要成套产品的场景(UI组件、游戏装备等)


五、三种模式核心对比

5.1 核心概念速览

cpp 复制代码
// 简单工厂:通过字符串参数创建对象
auto character = SimpleFactory::create("warrior");
// 工厂方法:每个产品对应专属工厂
WarriorFactory factory;
auto character = factory.create();
// 抽象工厂:创建配套产品系列
WarriorEquipmentFactory equipFactory;
auto weapon = equipFactory.createWeapon();  // 配套武器
auto armor = equipFactory.createArmor();    // 配套防具

5.2 模式选择指南

使用场景 推荐模式
产品类型少且稳定(<5种) 简单工厂
需要频繁扩展产品线 工厂方法 ⭐
需要确保产品兼容性 抽象工厂
快速开发原型 直接实例化

5.3 架构关系图解

复制代码
简单工厂:
  客户端 → [中央工厂] → 产品A/产品B/产品C
          (集中式生产)
工厂方法:
客户端 → 抽象工厂接口
├→ 工厂A → 产品A
├→ 工厂B → 产品B
└→ 工厂C → 产品C
(分散式生产)
抽象工厂:
客户端 → 抽象工厂接口
├→ 工厂X → 产品X1 + 产品X2
└→ 工厂Y → 产品Y1 + 产品Y2
(系列化生产)

六、最佳实践

6.1 应用场景判断

  • 代码中充斥new ConcreteClass() → 考虑简单工厂
  • 需要根据条件创建不同对象 → 采用工厂方法
  • 需要保持多对象风格一致 → 使用抽象工厂

6.2 C++实现要点

cpp 复制代码
// ✅ 最佳实践:使用智能指针管理资源
virtual std::unique_ptr<Product> create() = 0;
// ✅ 推荐:C++17智能指针构造
return std::make_unique<ConcreteProduct>();
// ❌ 反模式:返回原始指针
virtual Product* create() = 0;  // 存在内存泄漏风险

6.3 常见误区警示

  1. 避免过度使用:简单场景直接实例化更合适
  2. 模式认知:简单工厂是编程范式,非GoF标准模式
  3. 设计平衡:模式应用应以实际需求为准

七、代码资源

完整可编译的C++17示例代码已就绪。

编译指令:

bash 复制代码
# 简单工厂
g++ -std=c++17 simple_factory.cpp -o simple_factory
./simple_factory
工厂方法
g++ -std=c++17 factory_method.cpp -o factory_method
./factory_method
抽象工厂
g++ -std=c++17 abstract_factory.cpp -o abstract_factory
./abstract_factory

核心总结

本质原则:通过工厂模式实现对象创建与使用的解耦。

  • 简单工厂:中央集权式生产
  • 工厂方法:专业分工式生产
  • 抽象工厂:系列配套式生产

形象记忆法:简单工厂是"职业选择器"、工厂方法是"专业培训营"、抽象工厂是"风格套装生成器"。掌握这个类比,面试游刃有余!


推荐阅读:

  • 《Head First 设计模式》
  • GoF《设计模式:可复用面向对象软件的基础》

希望本指南助你彻底掌握工厂模式!如果觉得有帮助,欢迎点赞收藏~ 🎉

相关推荐
思茂信息1 小时前
电磁仿真学涉及哪些算法?
人工智能·算法·数学建模·matlab·emc·电磁仿真·仿真辐射
糖果豆豆2 小时前
让 AI 自查三遍,它只会把错的说得更像对的——检查的人和被检查的,是同一个
算法·架构
高晶3 小时前
2A3 单端甲类功放从零制作全攻略:电路设计、焊接调试到煲机维护一站式指南
前端·设计模式
把我格子衫拿来3 小时前
VTK 与 Qt 的 CMake 工程怎么组织?模块、工具链与二进制兼容排错
c++·qt·vtk·cmake·工程实践
总裁余(余登武)3 小时前
K-means算法改进(Python版)
python·算法·kmeans
灯澜忆梦3 小时前
【面向对象编程c++】| 指针与自定义数据类型
开发语言·c++·算法
xxwl5854 小时前
区域赛算法模版第八章---贪心(Greedy)
c++·笔记·学习·算法
雾沉川4 小时前
Visual C++运行库合集 v105.0 安装教程
开发语言·c++·dll
_wyt0014 小时前
洛谷P17461 [GESP202609 八级] 生成树计数 题解
c++·数学·树·gesp·八级·仙人掌