1. 从披萨店案例看抽象工厂模式的设计哲学
在面向对象编程中,抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种封装一组具有共同主题但实现细节不同的工厂的方法。这种模式在我们需要创建一系列相关或依赖对象时特别有用,而无需指定它们的具体类。
1.1 为什么我们需要抽象工厂
想象你经营一家披萨连锁店,在纽约和芝加哥都有分店。两家店虽然都卖披萨,但使用的原料却大不相同:纽约店用薄脆面团配马瑞纳拉酱,芝加哥店则偏好厚皮面团配李子番茄酱。如果为每个分店都写一套独立的代码,不仅维护困难,扩展新分店时也会遇到麻烦。
这就是抽象工厂要解决的问题。它让我们能够:
- 创建相关对象的家族而不需要指定具体类
- 将客户端代码与具体实现解耦
- 保证产品之间的兼容性
- 更容易扩展新产品系列
1.2 模式的核心结构
抽象工厂模式包含以下几个关键角色:
- 抽象工厂(AbstractFactory):声明创建抽象产品对象的接口
- 具体工厂(ConcreteFactory):实现创建具体产品对象的操作
- 抽象产品(AbstractProduct):为一类产品对象声明接口
- 具体产品(ConcreteProduct):定义具体工厂创建的产品对象
在披萨店的例子中:
PizzaIngredientFactory是抽象工厂NYPizzaIngredientFactory和ChicagoPizzaIngredientFactory是具体工厂Dough、Sauce等是抽象产品ThinCrustDough、MarinaraSauce等是具体产品
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从问题代码到设计原则
2.1 初始问题:紧耦合的代码
让我们先看一个典型的紧耦合实现:
cpp复制class DependentPizzaStore {
public:
Pizza* createPizza(const string& style, const string& type) {
Pizza* pizza = nullptr;
if (style == "NY") {
if (type == "cheese") pizza = new NYStyleCheesePizza();
else if (type == "greek") pizza = new NYStyleGreekPizza();
// 更多纽约风格披萨...
}
else if (style == "Chicago") {
if (type == "cheese") pizza = new ChicagoStyleCheesePizza();
else if (type == "greek") pizza = new ChicagoStyleGreekPizza();
// 更多芝加哥风格披萨...
}
// 披萨制作流程...
return pizza;
}
};
这段代码的问题很明显:
- 直接依赖具体披萨类
- 添加新风格需要修改现有代码
- 难以保证原料组合的正确性
- 违反开闭原则(对扩展开放,对修改关闭)
2.2 依赖倒置原则(DIP)
依赖倒置原则(Dependency Inversion Principle)是解决这个问题的关键。它包含两个核心观点:
- 高层模块不应该依赖于低层模块,两者都应该依赖于抽象
- 抽象不应该依赖于细节,细节应该依赖于抽象
在披萨店的上下文中:
- 高层模块:
PizzaStore(业务逻辑) - 低层模块:各种具体披萨类(实现细节)
- 抽象:
Pizza基类和PizzaIngredientFactory接口
应用DIP后,我们的设计变成了:
PizzaStore只依赖Pizza抽象类- 具体披萨类也依赖
Pizza抽象类 - 原料创建通过
PizzaIngredientFactory接口完成
3. 实现抽象工厂模式
3.1 定义原料工厂接口
首先,我们定义原料工厂的抽象接口:
cpp复制class PizzaIngredientFactory {
public:
virtual Dough* createDough() = 0;
virtual Sauce* createSauce() = 0;
virtual Cheese* createCheese() = 0;
virtual vector<Veggies*> createVeggies() = 0;
virtual Pepperoni* createPepperoni() = 0;
virtual Clams* createClam() = 0;
};
这个接口声明了创建各种原料的方法,但不指定具体实现。这让我们可以针对不同地区创建不同的实现。
3.2 实现具体工厂
对于纽约风格的披萨原料:
cpp复制class NYPizzaIngredientFactory : public PizzaIngredientFactory {
public:
Dough* createDough() override {
return new ThinCrustDough();
}
Sauce* createSauce() override {
return new MarinaraSauce();
}
Cheese* createCheese() override {
return new ReggianoCheese();
}
// 其他原料创建方法...
};
芝加哥风格的实现类似,但返回不同的具体产品:
cpp复制class ChicagoPizzaIngredientFactory : public PizzaIngredientFactory {
public:
Dough* createDough() override {
return new ThickCrustDough();
}
Sauce* createSauce() override {
return new PlumTomatoSauce();
}
// 其他原料创建方法...
};
3.3 重构披萨类
现在我们可以重构披萨类,让它使用原料工厂:
cpp复制class Pizza {
protected:
string name;
Dough* dough;
Sauce* sauce;
// 其他
