系列文章:
- 单例模式:【C++/Qt 进阶】设计模式系列(1):单例模式------饿汉式内存泄漏真相、指针单例存在的意义、五种实现终极对比-CSDN博客
- 工厂模式与抽象工厂模式(本篇)
- 建造者模式
- 原型模式
- 适配器模式
- 桥接模式(持续更新中)
前言
还记得初次接触工厂模式时,各种"产品""具体工厂""抽象产品"等专业术语让我一头雾水。直到我通过游戏角色创建 和披萨店运营这两个生活化案例来理解,才真正掌握其精髓。
本文将通过通俗易懂的讲解和完整的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;
}
主要问题:
- 创建逻辑分散,维护困难
- 客户端与具体类高度耦合
- 违反开闭原则(扩展需修改现有代码)
工厂模式的核心价值:封装对象创建过程,让客户端只需关注"使用什么",而不用关心"如何创建"。
二、简单工厂模式:角色创建中心
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 << "创建职业:" << player->getClassName() << "\n";
player->attack();
// 创建法师NPC
auto npc = SimpleCharacterFactory::createCharacter("mage");
std::cout << "创建职业:" << npc->getClassName() << "\n";
npc->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<Character> createCharacter() = 0;
// 模板方法:定义标准训练流程
void trainCharacter() {
auto character = createCharacter();
std::cout << "训练" << character->getClassName() << "完成!\n";
character->attack();
std::cout << "-------------------\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 << "\n=== " << getStoreName() << " ===\n";
pizza->prepare();
pizza->bake();
pizza->box();
std::cout << "请享用!\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 << "\n角色:" << name << "\n";
std::cout << "装备检查:\n";
weapon->use();
armor->equip();
std::cout << "--- 装备成套,属性匹配 ✅ ---\n";
}
};
int main() {
std::cout << "========== 抽象工厂模式演示 ==========\n";
// 创建战士角色
GameCharacter warrior("亚瑟",
std::make_unique<WarriorEquipmentFactory>());
warrior.showEquipment();
// 创建法师角色
GameCharacter mage("甘道夫",
std::make_unique<MageEquipmentFactory>());
mage.showEquipment();
// 创建弓箭手角色
GameCharacter archer("莱戈拉斯",
std::make_unique<ArcherEquipmentFactory>());
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 << "制作披萨:\n";
std::cout << " 面团:" << factory->createDough() << "\n";
std::cout << " 酱料:" << factory->createSauce() << "\n";
std::cout << " 芝士:" << factory->createCheese() << "\n";
std::cout << "所有原料来自同一产地 ✅\n";
}
};
int main() {
std::cout << "=== 意大利风情店 ===\n";
Pizza italianPizza(std::make_unique<ItalianIngredientFactory>());
italianPizza.prepare();
std::cout << "\n=== 有机健康店 ===\n";
Pizza organicPizza(std::make_unique<OrganicIngredientFactory>());
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 常见误区警示
- 避免过度使用:简单场景直接实例化更合适
- 模式认知:简单工厂是编程范式,非GoF标准模式
- 设计平衡:模式应用应以实际需求为准
七、代码资源
完整可编译的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《设计模式:可复用面向对象软件的基础》
希望本指南助你彻底掌握工厂模式!如果觉得有帮助,欢迎点赞收藏~ 🎉