Python 原型模式
想象一下你要制作一批相同的玩具汽车。你不会每次都从头开始设计制造,而是先制作一个完美的原型,然后基于这个原型进行复制。这就是原型模式的核心思想!
原型模式是一种创建型设计模式,它通过复制现有对象(原型)来创建新对象,而不是通过类来实例化。这种方式特别适合当创建对象的成本较高,或者需要创建多个相似对象时使用。
为什么需要原型模式?
让我们先看看传统创建对象的方式有什么问题:
实例
# 传统方式 - 每次都要重新创建
class Car:
def __init__(self, brand, model, color, engine_type):
self.brand = brand
self.model = model
self.color = color
self.engine_type = engine_type
# 假设这里有一些复杂的初始化逻辑
self.initialize_complex_components()
def initialize_complex_components(self):
# 模拟复杂的初始化过程
import time
time.sleep(1) # 假设初始化需要1秒钟
print(f"正在初始化 {self.brand} {self.model} 的复杂组件...")
# 创建多个相似对象
car1 = Car("Toyota", "Camry", "红色", "2.5L")
car2 = Car("Toyota", "Camry", "蓝色", "2.5L") # 需要重新执行复杂初始化
class Car:
def __init__(self, brand, model, color, engine_type):
self.brand = brand
self.model = model
self.color = color
self.engine_type = engine_type
# 假设这里有一些复杂的初始化逻辑
self.initialize_complex_components()
def initialize_complex_components(self):
# 模拟复杂的初始化过程
import time
time.sleep(1) # 假设初始化需要1秒钟
print(f"正在初始化 {self.brand} {self.model} 的复杂组件...")
# 创建多个相似对象
car1 = Car("Toyota", "Camry", "红色", "2.5L")
car2 = Car("Toyota", "Camry", "蓝色", "2.5L") # 需要重新执行复杂初始化
传统方式的缺点:
- 每次创建对象都要执行完整的初始化过程
- 如果初始化很复杂,会消耗大量时间和资源
- 代码重复,效率低下
原型模式的实现原理
原型模式通过让对象自己负责创建自己的副本来解决上述问题。在 Python 中,我们可以通过 copy 模块轻松实现原型模式。
核心组件

Python 中的复制机制
Python 提供了两种复制方式:
| 复制类型 | 方法 | 特点 | 适用场景 |
|---|---|---|---|
| 浅复制 | copy.copy() |
只复制对象本身,不复制嵌套对象 | 对象结构简单,没有嵌套引用 |
| 深复制 | copy.deepcopy() |
复制对象及其所有嵌套对象 | 对象结构复杂,有嵌套引用 |
实现原型模式
让我们通过一个完整的例子来学习如何实现原型模式。
基础实现
实例
import copy
from abc import ABC, abstractmethod
from typing import Any
class Prototype(ABC):
"""原型抽象基类"""
@abstractmethod
def clone(self) -> Any:
"""克隆方法 - 必须由子类实现"""
pass
class CarPrototype(Prototype):
"""汽车原型类"""
def __init__(self, brand: str, model: str, color: str, engine_type: str):
self.brand = brand
self.model = model
self.color = color
self.engine_type = engine_type
self.accessories = [] # 配件列表
self.initialize_complex_components()
def initialize_complex_components(self):
"""模拟复杂的初始化过程"""
print(f"正在初始化 {self.brand} {self.model} 的复杂组件...")
# 这里可以模拟一些耗时的初始化操作
def add_accessory(self, accessory: str):
"""添加配件"""
self.accessories.append(accessory)
def clone(self) -> 'CarPrototype':
"""实现克隆方法 - 使用深复制"""
return copy.deepcopy(self)
def display_info(self):
"""显示汽车信息"""
info = f"{self.brand} {self.model} - 颜色: {self.color}, 发动机: {self.engine_type}"
if self.accessories:
info += f", 配件: {', '.join(self.accessories)}"
print(info)
from abc import ABC, abstractmethod
from typing import Any
class Prototype(ABC):
"""原型抽象基类"""
@abstractmethod
def clone(self) -> Any:
"""克隆方法 - 必须由子类实现"""
pass
class CarPrototype(Prototype):
"""汽车原型类"""
def __init__(self, brand: str, model: str, color: str, engine_type: str):
self.brand = brand
self.model = model
self.color = color
self.engine_type = engine_type
self.accessories = [] # 配件列表
self.initialize_complex_components()
def initialize_complex_components(self):
"""模拟复杂的初始化过程"""
print(f"正在初始化 {self.brand} {self.model} 的复杂组件...")
# 这里可以模拟一些耗时的初始化操作
def add_accessory(self, accessory: str):
"""添加配件"""
self.accessories.append(accessory)
def clone(self) -> 'CarPrototype':
"""实现克隆方法 - 使用深复制"""
return copy.deepcopy(self)
def display_info(self):
"""显示汽车信息"""
info = f"{self.brand} {self.model} - 颜色: {self.color}, 发动机: {self.engine_type}"
if self.accessories:
info += f", 配件: {', '.join(self.accessories)}"
print(info)
使用示例
实例
# 创建原型对象
print("=== 创建原型对象 ===")
original_car = CarPrototype("Toyota", "Camry", "白色", "2.5L")
original_car.add_accessory("导航系统")
original_car.add_accessory("天窗")
original_car.display_info()
print("\n=== 通过克隆创建新对象 ===")
# 基于原型创建新对象
car1 = original_car.clone()
car1.color = "红色" # 只修改颜色
car1.display_info()
car2 = original_car.clone()
car2.color = "蓝色"
car2.add_accessory("真皮座椅") # 添加新配件
car2.display_info()
# 验证原型对象未被修改
print("\n=== 验证原型对象未被修改 ===")
original_car.display_info()
print("=== 创建原型对象 ===")
original_car = CarPrototype("Toyota", "Camry", "白色", "2.5L")
original_car.add_accessory("导航系统")
original_car.add_accessory("天窗")
original_car.display_info()
print("\n=== 通过克隆创建新对象 ===")
# 基于原型创建新对象
car1 = original_car.clone()
car1.color = "红色" # 只修改颜色
car1.display_info()
car2 = original_car.clone()
car2.color = "蓝色"
car2.add_accessory("真皮座椅") # 添加新配件
car2.display_info()
# 验证原型对象未被修改
print("\n=== 验证原型对象未被修改 ===")
original_car.display_info()
输出结果:
=== 创建原型对象 === 正在初始化 Toyota Camry 的复杂组件... Toyota Camry - 颜色: 白色, 发动机: 2.5L, 配件: 导航系统, 天窗 === 通过克隆创建新对象 === Toyota Camry - 颜色: 红色, 发动机: 2.5L, 配件: 导航系统, 天窗 Toyota Camry - 颜色: 蓝色, 发动机: 2.5L, 配件: 导航系统, 天窗, 真皮座椅 === 验证原型对象未被修改 === Toyota Camry - 颜色: 白色, 发动机: 2.5L, 配件: 导航系统, 天窗
高级应用场景
场景 1:游戏开发中的角色创建
实例
class GameCharacter(Prototype):
"""游戏角色原型"""
def __init__(self, name: str, character_class: str, level: int = 1):
self.name = name
self.character_class = character_class
self.level = level
self.skills = []
self.equipment = {}
self.initialize_character()
def initialize_character(self):
"""初始化角色 - 模拟复杂的数据加载"""
print(f"正在加载 {self.name} 的角色数据...")
# 模拟从数据库或配置文件加载数据
base_skills = {
"Warrior": ["斩击", "格挡", "冲锋"],
"Mage": ["火球术", "冰箭术", "传送术"],
"Archer": ["精准射击", "陷阱布置", "快速移动"]
}
self.skills = base_skills.get(self.character_class, [])
def add_skill(self, skill: str):
"""添加技能"""
self.skills.append(skill)
def equip_item(self, slot: str, item: str):
"""装备物品"""
self.equipment[slot] = item
def clone(self) -> 'GameCharacter':
"""克隆角色"""
return copy.deepcopy(self)
def show_status(self):
"""显示角色状态"""
print(f"角色: {self.name} ({self.character_class}) - 等级: {self.level}")
print(f"技能: {', '.join(self.skills)}")
if self.equipment:
equipment_str = ', '.join([f"{k}: {v}" for k, v in self.equipment.items()])
print(f"装备: {equipment_str}")
# 使用示例
print("=== 游戏角色原型示例 ===")
warrior_template = GameCharacter("战士模板", "Warrior")
warrior_template.equip_item("武器", "钢铁长剑")
warrior_template.equip_item("护甲", "锁子甲")
warrior_template.show_status()
print("\n=== 创建玩家角色 ===")
player1 = warrior_template.clone()
player1.name = "勇敢的冒险者"
player1.level = 5
player1.add_skill("旋风斩")
player1.show_status()
player2 = warrior_template.clone()
player2.name = "无畏的守护者"
player2.level = 3
player2.equip_item("盾牌", "钢铁盾牌")
player2.show_status()
"""游戏角色原型"""
def __init__(self, name: str, character_class: str, level: int = 1):
self.name = name
self.character_class = character_class
self.level = level
self.skills = []
self.equipment = {}
self.initialize_character()
def initialize_character(self):
"""初始化角色 - 模拟复杂的数据加载"""
print(f"正在加载 {self.name} 的角色数据...")
# 模拟从数据库或配置文件加载数据
base_skills = {
"Warrior": ["斩击", "格挡", "冲锋"],
"Mage": ["火球术", "冰箭术", "传送术"],
"Archer": ["精准射击", "陷阱布置", "快速移动"]
}
self.skills = base_skills.get(self.character_class, [])
def add_skill(self, skill: str):
"""添加技能"""
self.skills.append(skill)
def equip_item(self, slot: str, item: str):
"""装备物品"""
self.equipment[slot] = item
def clone(self) -> 'GameCharacter':
"""克隆角色"""
return copy.deepcopy(self)
def show_status(self):
"""显示角色状态"""
print(f"角色: {self.name} ({self.character_class}) - 等级: {self.level}")
print(f"技能: {', '.join(self.skills)}")
if self.equipment:
equipment_str = ', '.join([f"{k}: {v}" for k, v in self.equipment.items()])
print(f"装备: {equipment_str}")
# 使用示例
print("=== 游戏角色原型示例 ===")
warrior_template = GameCharacter("战士模板", "Warrior")
warrior_template.equip_item("武器", "钢铁长剑")
warrior_template.equip_item("护甲", "锁子甲")
warrior_template.show_status()
print("\n=== 创建玩家角色 ===")
player1 = warrior_template.clone()
player1.name = "勇敢的冒险者"
player1.level = 5
player1.add_skill("旋风斩")
player1.show_status()
player2 = warrior_template.clone()
player2.name = "无畏的守护者"
player2.level = 3
player2.equip_item("盾牌", "钢铁盾牌")
player2.show_status()
场景 2:文档模板系统
实例
class DocumentTemplate(Prototype):
"""文档模板原型"""
def __init__(self, template_name: str):
self.template_name = template_name
self.headers = {}
self.content_sections = []
self.styles = {}
self.load_template_config()
def load_template_config(self):
"""加载模板配置 - 模拟复杂的配置加载"""
print(f"正在加载 {self.template_name} 模板配置...")
# 模拟从文件或数据库加载配置
self.headers = {
"title": f"{self.template_name} 文档",
"author": "系统生成",
"date": "2024-01-01"
}
self.styles = {
"font_family": "Arial",
"font_size": "12pt",
"line_spacing": "1.5"
}
def clone(self) -> 'DocumentTemplate':
"""克隆文档模板"""
return copy.deepcopy(self)
def customize(self, title: str = None, author: str = None):
"""自定义文档"""
if title:
self.headers["title"] = title
if author:
self.headers["author"] = author
self.headers["date"] = "2024-12-19" # 更新日期
def add_section(self, section_title: str, content: str):
"""添加内容章节"""
self.content_sections.append({
"title": section_title,
"content": content
})
def render(self):
"""渲染文档"""
print(f"\n=== {self.headers['title']} ===")
print(f"作者: {self.headers['author']}")
print(f"日期: {self.headers['date']}")
print(f"样式: {self.styles}")
for section in self.content_sections:
print(f"\n## {section['title']}")
print(section['content'])
print("=" * 50)
# 使用示例
print("=== 文档模板系统 ===")
report_template = DocumentTemplate("标准报告")
report_template.add_section("简介", "这是报告的简介部分。")
report_template.render()
print("\n=== 创建具体报告 ===")
monthly_report = report_template.clone()
monthly_report.customize("月度销售报告", "销售部")
monthly_report.add_section("销售数据", "本月销售额达到100万元。")
monthly_report.render()
project_report = report_template.clone()
project_report.customize("项目进度报告", "项目经理")
project_report.add_section("项目进展", "项目按计划进行中。")
project_report.render()
"""文档模板原型"""
def __init__(self, template_name: str):
self.template_name = template_name
self.headers = {}
self.content_sections = []
self.styles = {}
self.load_template_config()
def load_template_config(self):
"""加载模板配置 - 模拟复杂的配置加载"""
print(f"正在加载 {self.template_name} 模板配置...")
# 模拟从文件或数据库加载配置
self.headers = {
"title": f"{self.template_name} 文档",
"author": "系统生成",
"date": "2024-01-01"
}
self.styles = {
"font_family": "Arial",
"font_size": "12pt",
"line_spacing": "1.5"
}
def clone(self) -> 'DocumentTemplate':
"""克隆文档模板"""
return copy.deepcopy(self)
def customize(self, title: str = None, author: str = None):
"""自定义文档"""
if title:
self.headers["title"] = title
if author:
self.headers["author"] = author
self.headers["date"] = "2024-12-19" # 更新日期
def add_section(self, section_title: str, content: str):
"""添加内容章节"""
self.content_sections.append({
"title": section_title,
"content": content
})
def render(self):
"""渲染文档"""
print(f"\n=== {self.headers['title']} ===")
print(f"作者: {self.headers['author']}")
print(f"日期: {self.headers['date']}")
print(f"样式: {self.styles}")
for section in self.content_sections:
print(f"\n## {section['title']}")
print(section['content'])
print("=" * 50)
# 使用示例
print("=== 文档模板系统 ===")
report_template = DocumentTemplate("标准报告")
report_template.add_section("简介", "这是报告的简介部分。")
report_template.render()
print("\n=== 创建具体报告 ===")
monthly_report = report_template.clone()
monthly_report.customize("月度销售报告", "销售部")
monthly_report.add_section("销售数据", "本月销售额达到100万元。")
monthly_report.render()
project_report = report_template.clone()
project_report.customize("项目进度报告", "项目经理")
project_report.add_section("项目进展", "项目按计划进行中。")
project_report.render()
原型模式的优缺点
优点
- 性能优化:避免重复执行昂贵的初始化操作
- 简化创建过程:客户端不需要了解对象创建的细节
- 动态配置:可以在运行时动态添加或删除产品
- 减少子类:不需要为每种产品创建对应的子类
缺点
- 复制复杂性:对于包含循环引用的复杂对象,复制可能很复杂
- 内存使用:如果原型对象很大,复制可能消耗较多内存
- 深复制开销:深复制可能比创建新实例更耗时
最佳实践和注意事项
1. 选择合适的复制方式
实例
class SmartPrototype(Prototype):
def __init__(self, data):
self.data = data
self.reference_data = [] # 可能需要共享的数据
def clone(self):
"""智能复制:根据需求选择浅复制或深复制"""
new_obj = copy.copy(self) # 浅复制主体
new_obj.reference_data = self.reference_data # 共享引用数据
new_obj.data = copy.deepcopy(self.data) # 深复制重要数据
return new_obj
def __init__(self, data):
self.data = data
self.reference_data = [] # 可能需要共享的数据
def clone(self):
"""智能复制:根据需求选择浅复制或深复制"""
new_obj = copy.copy(self) # 浅复制主体
new_obj.reference_data = self.reference_data # 共享引用数据
new_obj.data = copy.deepcopy(self.data) # 深复制重要数据
return new_obj
2. 处理循环引用
实例
class Node(Prototype):
def __init__(self, value):
self.value = value
self.children = []
def add_child(self, child):
self.children.append(child)
def clone(self):
"""处理可能存在的循环引用"""
# 使用深复制会自动处理循环引用
return copy.deepcopy(self)
def __init__(self, value):
self.value = value
self.children = []
def add_child(self, child):
self.children.append(child)
def clone(self):
"""处理可能存在的循环引用"""
# 使用深复制会自动处理循环引用
return copy.deepcopy(self)
3. 原型注册表模式
实例
class PrototypeRegistry:
"""原型注册表 - 管理多个原型"""
def __init__(self):
self._prototypes = {}
def register_prototype(self, name: str, prototype: Prototype):
"""注册原型"""
self._prototypes[name] = prototype
def unregister_prototype(self, name: str):
"""取消注册原型"""
if name in self._prototypes:
del self._prototypes[name]
def clone_prototype(self, name: str) -> Prototype:
"""根据名称克隆原型"""
if name not in self._prototypes:
raise ValueError(f"原型 {name} 未注册")
return self._prototypes[name].clone()
def list_prototypes(self):
"""列出所有可用的原型"""
return list(self._prototypes.keys())
# 使用注册表
registry = PrototypeRegistry()
registry.register_prototype("basic_car", CarPrototype("Toyota", "Camry", "白色", "2.5L"))
registry.register_prototype("warrior", GameCharacter("战士", "Warrior"))
# 快速创建对象
new_car = registry.clone_prototype("basic_car")
new_warrior = registry.clone_prototype("warrior")
"""原型注册表 - 管理多个原型"""
def __init__(self):
self._prototypes = {}
def register_prototype(self, name: str, prototype: Prototype):
"""注册原型"""
self._prototypes[name] = prototype
def unregister_prototype(self, name: str):
"""取消注册原型"""
if name in self._prototypes:
del self._prototypes[name]
def clone_prototype(self, name: str) -> Prototype:
"""根据名称克隆原型"""
if name not in self._prototypes:
raise ValueError(f"原型 {name} 未注册")
return self._prototypes[name].clone()
def list_prototypes(self):
"""列出所有可用的原型"""
return list(self._prototypes.keys())
# 使用注册表
registry = PrototypeRegistry()
registry.register_prototype("basic_car", CarPrototype("Toyota", "Camry", "白色", "2.5L"))
registry.register_prototype("warrior", GameCharacter("战士", "Warrior"))
# 快速创建对象
new_car = registry.clone_prototype("basic_car")
new_warrior = registry.clone_prototype("warrior")
实践练习
现在轮到你了!尝试完成以下练习来巩固对原型模式的理解:
练习 1:改进汽车原型
修改 CarPrototype 类,添加以下功能:
- 记录汽车的制造日期
- 添加车辆识别码 (VIN) 生成逻辑
- 实现一个方法来判断两个汽车对象是否相同
练习 2:创建配置管理器
设计一个配置管理器原型,要求:
- 能够存储应用的配置信息
- 支持配置的克隆和自定义
- 提供配置验证功能
练习 3:实现原型缓存
创建一个带缓存的原型系统:
- 缓存常用的原型对象
- 提供缓存的清理和更新机制
- 支持原型的版本管理
总结
原型模式是 Python 中一个非常实用的设计模式,它通过复制现有对象来创建新对象,特别适合以下场景:
- 对象创建成本高:当创建新对象的初始化过程很复杂或耗时
- 需要相似对象:当需要创建多个相似但略有不同的对象
- 动态配置:当对象的配置可能在运行时改变
关键要点:
- 使用
copy模块实现复制功能 - 根据需求选择浅复制或深复制
- 考虑使用原型注册表来管理多个原型
- 注意处理循环引用和内存使用问题
点我分享笔记