本文目录导读:

- 📖 目录导读
- 什么是工厂模式?——从生活案例理解核心思想
- 工厂模式解决什么问题?——代码耦合与扩展困境
- Python实现简单工厂模式——披萨店案例
- 进阶:工厂方法模式——产品线分化
- 实战:抽象工厂模式——跨平台UI组件
- 常见问题与避坑指南(问答环节)
- 总结与最佳实践建议
Python案例精讲:如何用代码实现工厂模式?一篇搞定设计模式实战
📖 目录导读
- 什么是工厂模式?——从生活案例理解核心思想
- 工厂模式解决什么问题?——代码耦合与扩展困境
- Python实现简单工厂模式——披萨店案例
- 进阶:工厂方法模式——产品线分化
- 实战:抽象工厂模式——跨平台UI组件
- 常见问题与避坑指南(问答环节)
- 总结与最佳实践建议
什么是工厂模式?——从生活案例理解核心思想
想象你开了一家披萨店,客人点餐时,你不需要告诉客人“我需要先揉面、发酵、切蔬菜……”——你只需要一个点单动作,厨房就会自动生产出对应口味的披萨,这个过程,就是工厂模式在现实世界的映射。
工厂模式本质是一种创建型设计模式,它将对象的创建过程封装起来,客户端只需通过一个统一接口请求产品,而无需关心具体的实例化逻辑,用Python术语说:你只调用factory.create_pizza("cheese"),而不需要写if type == "cheese": return CheesePizza()这种散落在各处的条件分支。
从搜索引擎优化(SEO)角度看,这个主题的搜索意图高度集中在“Python工厂模式代码怎么写”“工厂模式案例”上,因此本文会直接给出可运行的代码,并解释为什么这样写。
工厂模式解决什么问题?——代码耦合与扩展困境
假设没有工厂模式,你可能会这样写披萨制作逻辑:
class SimplePizzaStore:
def order_pizza(self, pizza_type):
if pizza_type == "cheese":
pizza = CheesePizza()
elif pizza_type == "veggie":
pizza = VeggiePizza()
elif pizza_type == "pepperoni":
pizza = PepperoniPizza()
else:
raise ValueError("Unknown pizza type")
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
return pizza
问题分析:
- 每次新增披萨类型(海鲜披萨”),都要修改
order_pizza函数,违反开闭原则。 - 创建逻辑与业务逻辑混合,难以维护和单元测试。
- 如果披萨构造过程复杂(需要不同面团、酱料),代码会迅速膨胀。
这正是工厂模式要解决的耦合问题——将“创建对象”和“使用对象”解耦。
Python实现简单工厂模式——披萨店案例
我们先实现最基础的简单工厂模式(负责创建披萨的中心工厂类):
from abc import ABC, abstractmethod
# 产品基类
class Pizza(ABC):
@abstractmethod
def get_description(self):
pass
def prepare(self): pass
def bake(self): pass
def cut(self): pass
def box(self): pass
# 具体产品
class CheesePizza(Pizza):
def get_description(self):
return "Cheese Pizza with mozzarella"
class VeggiePizza(Pizza):
def get_description(self):
return "Veggie Pizza with fresh vegetables"
class PepperoniPizza(Pizza):
def get_description(self):
return "Pepperoni Pizza with spicy sausage"
# 工厂类
class SimplePizzaFactory:
def create_pizza(self, pizza_type: str) -> Pizza:
pizza_map = {
"cheese": CheesePizza,
"veggie": VeggiePizza,
"pepperoni": PepperoniPizza
}
pizza_class = pizza_map.get(pizza_type)
if not pizza_class:
raise ValueError(f"Pizza type {pizza_type} not available")
return pizza_class()
# 使用工厂
class PizzaStore:
def __init__(self, factory: SimplePizzaFactory):
self.factory = factory
def order_pizza(self, pizza_type):
pizza = self.factory.create_pizza(pizza_type)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
print(f"Delivering {pizza.get_description()}")
return pizza
# 客户端代码
if __name__ == "__main__":
factory = SimplePizzaFactory()
store = PizzaStore(factory)
store.order_pizza("cheese")
store.order_pizza("veggie")
关键点:工厂方法通过字典映射代替if-elif链,新增产品只需在字典中添加一项,无需修改现有代码。
进阶:工厂方法模式——产品线分化
当披萨店扩张,不同地区(纽约、芝加哥)的披萨制作工艺不同,简单工厂就不够用了,我们需要工厂方法模式:让子类决定实例化哪一个具体产品。
class PizzaStore(ABC):
@abstractmethod
def create_pizza(self, pizza_type: str) -> Pizza:
pass
def order_pizza(self, pizza_type):
pizza = self.create_pizza(pizza_type)
pizza.prepare()
pizza.bake()
pizza.cut()
pizza.box()
print(f"Delivering {pizza.get_description()}")
return pizza
class NYPizzaStore(PizzaStore):
def create_pizza(self, pizza_type):
if pizza_type == "cheese":
return NYStyleCheesePizza()
elif pizza_type == "veggie":
return NYStyleVeggiePizza()
# ... 纽约风味的披萨类实现略
class ChicagoPizzaStore(PizzaStore):
def create_pizza(self, pizza_type):
if pizza_type == "cheese":
return ChicagoStyleCheesePizza()
# ... 芝加哥风味的披萨类实现略
亮点:每个地区商店通过子类实现自己的create_pizza,添加新地区时无需修改已有代码,每个地区的披萨虽然类型相同,但原料、厚度、烘烤方式都可以不同。
实战:抽象工厂模式——跨平台UI组件
当涉及产品族(例如同一操作系统下的按钮、文本框、菜单)时,使用抽象工厂模式,这是最复杂的工厂模式,但最适合处理跨平台开发。
假设我们要构建跨平台UI组件(macOS vs Windows):
# 抽象产品接口
class Button(ABC):
@abstractmethod
def render(self): pass
class TextBox(ABC):
@abstractmethod
def render(self): pass
# 具体产品族1: macOS
class MacButton(Button):
def render(self):
print("Rendering Mac-style button")
class MacTextBox(TextBox):
def render(self):
print("Rendering Mac-style text box")
# 具体产品族2: Windows
class WinButton(Button):
def render(self):
print("Rendering Windows-style button")
class WinTextBox(TextBox):
def render(self):
print("Rendering Windows-style text box")
# 抽象工厂
class UIFactory(ABC):
@abstractmethod
def create_button(self) -> Button: pass
@abstractmethod
def create_textbox(self) -> TextBox: pass
# 具体工厂
class MacFactory(UIFactory):
def create_button(self):
return MacButton()
def create_textbox(self):
return MacTextBox()
class WinFactory(UIFactory):
def create_button(self):
return WinButton()
def create_textbox(self):
return WinTextBox()
# 客户端代码
class Application:
def __init__(self, factory: UIFactory):
self.button = factory.create_button()
self.textbox = factory.create_textbox()
def render(self):
self.button.render()
self.textbox.render()
# 假设通过配置决定使用哪个工厂
if __name__ == "__main__":
platform = "mac" # 实际可能来自配置文件
factory = MacFactory() if platform == "mac" else WinFactory()
app = Application(factory)
app.render()
设计精髓:客户端只需知道抽象工厂接口,无需关心具体操作系统细节,添加新的操作系统(如Linux)时,只需实现对应的产品族和工厂,无需修改现有代码。
常见问题与避坑指南(问答环节)
Q1:简单工厂模式到底算不算设计模式?
A:简单工厂不是GoF的23种设计模式之一,更像是一种编程习惯,但它为理解工厂方法模式打下基础。
Q2:什么时候用工厂方法,什么时候用抽象工厂?
A:如果产品之间没有“族”的关系(比如只创建披萨,不创建饮料),用工厂方法;如果存在产品族(如不同平台的按钮+文本框),用抽象工厂。
Q3:Python的类本身就是工厂吗?直接Pizza("cheese")不行吗?
A:直接实例化会带来客户端耦合,当创建逻辑复杂(需要连接数据库、读取配置、依赖注入),或者需要控制实例数量时,工厂模式优势明显。
Q4:工厂模式和策略模式有什么区别?
A:工厂是创建型模式(怎么造对象),策略是行为型模式(怎么执行算法),工厂生成对象后,还可以用策略模式来封装变化的行为。
总结与最佳实践建议
- 代码可扩展性:当产品类型可能增加时,优先使用工厂模式替代硬编码条件判断。
- 命名规范:工厂类名建议以
Factory方法名用create_或build_,提高代码可读性。 - Python特有优化:利用
__init_subclass__或functools.singledispatch也可以实现类似工厂的效果,但会降低显式性。 - 测试友好:工厂模式使得在单元测试中可以轻松替换为Mock产品对象。
如果你想在真实项目中实践,可以从数据库连接工厂、日志记录器工厂这类场景开始——它们通常需要根据配置动态创建不同实现,设计模式不是银弹,当创建逻辑足够简单时,直接new也完全没问题。
最后一道自测题:如果现在要为一个游戏添加“武器系统”,武器类型包含剑、弓、法杖,每种武器又有普通、稀有、传说三个品质,你会选择哪种工厂模式?欢迎在评论区写出你的设计方案。