<摘要>
工厂方法模式就像一个万能玩具工厂,爸爸(抽象工厂)定义了制作玩具的标准流程,但让儿子们(具体工厂)决定具体生产哪种玩具。这种模式解决了"既要规范生产流程,又要灵活适应变化"的矛盾,通过将对象创建延迟到子类实现,让系统扩展像搭积木一样简单自然。本文将通过玩具工厂、披萨店和游戏武器三个生动故事,完整展示工厂方法模式在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 工厂方法模式的童话解读
想象工厂方法模式就像一个乐高积木说明书:
- 抽象产品(Toy):说明书上说"这里要放一个可以玩的部件"
- 具体产品(WoodenCar/PlasticRobot):实际拿到的积木块
- 抽象工厂(ToyFactory):说明书上的组装步骤
- 具体工厂(PlasticToyFactory):你按照说明书实际组装的过程
玩具大师 +制定标准() <<抽象>> 玩具工厂 +创建玩具() 大儿子工厂 +创建玩具() 二儿子工厂 +创建玩具() <<接口>> 玩具 +玩耍() 塑料玩具 电子玩具
2.2 三个关键角色
- 玩具大师(Client):想要玩具的孩子,不关心玩具怎么来的
- 工厂说明书(Creator):定义"如何生产玩具"的流程
- 具体工厂(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组件
- 🏭 制造业中不同生产线生产类似但不同的产品
通过这个生动的故事和实际代码示例,相信你已经深刻理解了工厂方法模式的精髓。记住:好的设计不是什么都自己做,而是定义好规则,让他人自由发挥!