工厂的智慧:工厂方法与抽象工厂
凌晨五点半,“环球美味”中央厨房的灯光已经亮起。主厨王站在巨大的订单显示屏前,深吸一口气。屏幕上闪烁着一串数字:北京-宫保鸡丁×20,罗马-玛格丽特披萨×30,墨西哥城-塔可×25。这不是普通的早餐订单,而是“环球美味”在全球扩张后面临的新常态——每个分店都坚持本地化正宗口味,但中央厨房的生产线却像一台老旧的缝纫机,试图缝制西装、旗袍和牛仔服。<!-- 模式引入: 对象创建的多样性挑战 --> “如果我们继续让所有厨师学习所有菜系,”王对架构师李说,“不仅培训成本爆炸,而且每道菜的灵魂都会丢失。Chinese cuisine needs wok hei, Italian pizza demands a wood-fired oven, Mexican tacos require fresh corn tortillas——each is a universe of its own.” 李推了推眼镜,微笑道:“这正是创建型设计模式要解决的:如何让系统灵活地创建对象,而不被具体类绑死。”
问题的根源在于代码的僵化。早期,系统只有一个`create_dish()`函数,用巨大的`if-elif-else`链判断菜系:```python
反模式:紧耦合的对象创建
def create_dish(cuisine_type, order_details): if cuisine_type == "chinese": return ChineseDish(order_details) elif cuisine_type == "italian": return ItalianDish(order_details) elif cuisine_type == "mexican": return MexicanDish(order_details) else: raise ValueError("Unknown cuisine") ``` 每添加一个新菜系,就必须修改这个函数——这违反了开闭原则(Open/Closed Principle)。更糟的是,`create_dish`还隐含知道所有菜品的构造细节,客户端(订单系统)与具体菜品类直接耦合。当北京分店要求增加“川菜”子类,或罗马分店需要“那不勒斯披萨”变体时,修改如涟漪般扩散,测试成本飙升。主厨王比喻道:“这就像要求一个厨师同时精通八大菜系,而且每天都要重新学习新菜谱——不可能,也不可持续。”
李在白板上画了一个简单的图:```mermaid graph LR A[客户端 Client] --> B[创建函数 Creator] B --> C{判断类型} C --> D[具体产品 A] C --> E[具体产品 B] D --> F[客户端使用] E --> F ``` “看,”李解释,“客户端直接依赖创建逻辑和所有具体产品。我们需要把‘创建’的决策权交还给每个菜系自己,同时让客户端只与抽象交互。这就是工厂方法模式(Factory Method Pattern)的核心:定义一个创建对象的接口,但让子类决定实例化哪个类。工厂方法让类的实例化推迟到子类。”
第二天,厨房改革启动。总厨房(`CentralKitchen`)被重构为一个抽象基类,声明一个`prepare_dish()`的工厂方法,但不实现具体逻辑:```python from abc import ABC, abstractmethod
产品抽象:所有菜品必须实现的接口
class Dish(ABC): @abstractmethod def cook(self): pass
@abstractmethod def describe(self): pass
创建者抽象:声明工厂方法
class Kitchen(ABC):
工厂方法:子类将重写此方法以创建具体产品
def prepare_dish(self, order_details) -> Dish: dish = self._create_dish(order_details) # 调用工厂方法 dish.cook() return dish
@abstractmethod def _create_dish(self, order_details) -> Dish: """子类必须实现此工厂方法""" pass ``` 然后,每个菜系厨房作为具体创建者(`ConcreteCreator`),继承`Kitchen`并实现`_create_dish`:```python
具体产品:中式菜品
class KungPaoChicken(Dish): def cook(self): print("Wok-frying chicken with peanuts and chili.")
def describe(self): return "Spicy Sichuan-style Kung Pao Chicken"
def _create_dish(self, order_details) -> Dish:
中式厨房专属创建逻辑
return KungPaoChicken()
class ItalianKitchen(Kitchen): def _create_dish(self, order_details) -> Dish: dish_type = order_details.get("type", "margherita") if dish_type == "margherita": return MargheritaPizza() elif dish_type == "carbonara": return SpaghettiCarbonara() else: raise ValueError(f"Unknown Italian dish: {dish_type}")
class MexicanKitchen(Kitchen): def _create_dish(self, order_details) -> Dish: return BeefTaco() ``` 客户端(订单处理系统)现在只与`Kitchen`抽象交互:```python
客户端代码:完全不知道具体菜品类
def process_order(cuisine, kitchen: Kitchen, order_details): print(f"Processing {cuisine} order...") dish = kitchen.prepare_dish(order_details) print(f"Serving: {dish.describe()}")
使用示例
chinese_kitchen = ChineseKitchen() process_order("Chinese", chinese_kitchen, {"spicy_level": 3})
italian_kitchen = ItalianKitchen() process_order("Italian", italian_kitchen, {"type": "carbonara"}) ``` 工厂方法模式的关键在于:`Kitchen.prepare_dish()`定义了创建流程的骨架(调用`_create_dish`然后烹饪),但把具体创建推迟到子类。这带来三大好处:第一,单一职责:每个厨房只负责自己的菜品创建,代码内聚;第二,开闭原则:添加新菜系只需新建`JapaneseKitchen`类,不修改现有`Kitchen`或客户端;第三,客户端解耦:订单系统只依赖`Kitchen`抽象,不感知`KungPaoChicken`或`MargheritaPizza`的存在。
主厨王很快发现了新问题。一天,罗马分店投诉:“我们的玛格丽特披萨配的是中式竹筷,而北京分店的宫保鸡丁却用着意大利 marble 餐桌——品牌形象混乱!” 原来,工厂方法只解决了“菜品”的创建,但餐厅体验是产品族(product family):一道菜需要配套的餐具、桌椅、甚至背景音乐。如果客户端分别创建菜品、餐具、家具,很容易混搭出错。例如,意式厨房可能创建了披萨,却错误地配了筷子。李在白板上画出新的困境:```mermaid graph TD Client -->|创建| Kitchen1[ChineseKitchen] Client -->|创建| TableFactory[TableFactory] Kitchen1 -->|返回| Dish1[KungPao] TableFactory -->|返回| Table1[ChineseTable] Table1 -.->|可能错配| Dish1 ``` “我们需要一个能同时创建相关对象的工厂,”李说,“而且这些对象必须属于同一风格族。这就是抽象工厂模式(Abstract Factory Pattern):提供一个接口,用于创建相关或依赖对象的家族,而不需要依赖具体类。”
抽象工厂将工厂方法提升一个层次:不是为每个产品类型(菜品、餐具)单独设工厂,而是定义一个能生产整套“主题”的超级工厂。代码重构如下:```python
抽象工厂:声明创建整个产品族的方法
class RestaurantFactory(ABC): @abstractmethod def create_dish(self) -> Dish: pass
@abstractmethod def create_cutlery(self) -> Cutlery: pass
@abstractmethod def create_furniture(self) -> Furniture: pass
具体工厂:实现整个产品族
class ChineseRestaurantFactory(RestaurantFactory): def create_dish(self) -> Dish: return KungPaoChicken()
def create_cutlery(self) -> Cutlery: return BambooChopsticks()
def create_furniture(self) -> Furniture: return ChineseTeaTable()
class ItalianRestaurantFactory(RestaurantFactory): def create_dish(self) -> Dish: return MargheritaPizza()
def create_cutlery(self) -> Cutlery: return ForkAndKnife()
def create_furniture(self) -> Furniture: return MarbleTable() ``` 客户端现在只需获取一个工厂,就能获得风格统一的所有对象:```python def setup_restaurant(factory: RestaurantFactory): dish = factory.create_dish() cutlery = factory.create_cutlery() furniture = factory.create_furniture()
所有对象自动属于同一主题
print(f"Menu: {dish.describe()}, Utensils: {cutlery.material}, Table: {furniture.style}") return dish, cutlery, furniture
使用
chinese_factory = ChineseRestaurantFactory() setup_restaurant(chinese_factory) # 全部中式
italian_factory = ItalianRestaurantFactory() setup_restaurant(italian_factory) # 全部意式 ``` 抽象工厂通过一个接口封装了多个工厂方法,确保产品族的一致性。其类结构可用PlantUML清晰展示:```plantuml @startuml interface RestaurantFactory { +create_dish() : Dish +create_cutlery() : Cutlery +create_furniture() : Furniture }
class ChineseRestaurantFactory { +create_dish() : Dish +create_cutlery() : Cutlery +create_furniture() : Furniture }
class ItalianRestaurantFactory { +create_dish() : Dish +create_cutlery() : Cutlery +create_furniture() : Furniture }
class KungPaoChicken implements Dish class BambooChopsticks implements Cutlery class ChineseTeaTable implements Furniture
class MargheritaPizza implements Dish class ForkAndKnife implements Cutlery class MarbleTable implements Furniture
ChineseRestaurantFactory --> KungPaoChicken : creates > ChineseRestaurantFactory --> BambooChopsticks : creates > ChineseRestaurantFactory --> ChineseTeaTable : creates >
ItalianRestaurantFactory --> MargheritaPizza : creates > ItalianRestaurantFactory --> ForkAndKnife : creates > ItalianRestaurantFactory --> MarbleTable : creates > @enduml ``` 这张图揭示了抽象工厂的本质:工厂的工厂。`RestaurantFactory`是抽象工厂,`ChineseRestaurantFactory`和`ItalianRestaurantFactory`是具体工厂,它们各自创建属于同一“家族”的产品(中式或意式)。
工厂方法与抽象工厂的核心区别在于产品范围。工厂方法处理单个产品(如只创建菜品),而抽象工厂处理产品族(菜品+餐具+家具)。用餐厅比喻:工厂方法像是每个菜系有自己的“主厨”负责做菜;抽象工厂像是每个菜系有一个“总承包商”,负责从菜品到装修的一切。这也导致了两者的扩展性差异:工厂方法添加新产品类型(如新增“饮料”)只需在每个具体厨房添加新方法;而抽象工厂添加新产品类型(如新增“音乐系统”)需要修改`RestaurantFactory`接口及所有具体工厂——这违反了开闭原则。因此,抽象工厂适用于产品族相对稳定的场景(如GUI组件:按钮、文本框、滚动条必须风格一致),而工厂方法更适合产品类型频繁变动的场景。
“那么,我们该选哪个?”主厨王问。李展示了决策矩阵:| 场景 | 推荐模式 | 原因 | |------|---------|------| | 创建单一类型对象,且未来可能新增类型 | 工厂方法 | 扩展容易,只需新增具体创建者 | | 需要保证多个相关对象的一致性(如跨平台GUI) | 抽象工厂 | 强制产品族统一,避免混搭 | | 对象创建逻辑复杂,需复用创建流程 | 工厂方法 | 模板方法模式常与之结合 | | 系统需独立于如何创建、组合和表示产品 | 抽象工厂 | 完全封装产品族 |
在“环球美味”的实际部署中,他们混合使用了两种模式。中央订单系统使用工厂方法动态选择厨房(`Kitchen`子类),因为新菜系(如日料、法餐)会不断加入。而每个厨房内部,使用抽象工厂创建整套餐厅设施,因为一旦选定菜系,餐具、家具就必须严格匹配。这种分层架构既保持了顶层灵活,又确保了底层一致。
代码层面的实现也体现了这种混合。例如,`ChineseKitchen`(工厂方法的具体创建者)内部持有一个`ChineseRestaurantFactory`实例:```python class ChineseKitchen(Kitchen): def __init__(self): self.factory = ChineseRestaurantFactory() # 组合抽象工厂
def _create_dish(self, order_details) -> Dish:
工厂方法只负责菜品,但可以调用工厂获取其他配套
dish = self.factory.create_dish()
可选:同时准备餐具
cutlery = self.factory.create_cutlery() return dish ``` 这种组合展示了设计模式的可组合性——模式不是互斥的,而是可以协作解决复杂问题。
几周后,“环球美味”在全球新增了5个菜系,系统零修改。主厨王在员工大会上举起一双竹筷和一把叉