You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

366 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
原型模式 (Prototype Pattern)
意图:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。
应用场景:
- 当要实例化的类是在运行时刻指定时,例如,通过动态加载
- 为了避免创建一个与产品类层次平行的工厂类层次时
- 当一个类的实例只能有几个不同状态组合中的一种时,建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便
结构:
- Prototype: 声明一个克隆自身的接口
- ConcretePrototype: 实现克隆自身的操作
- Client: 让一个原型克隆自身以创建一个新的对象
"""
from abc import ABC, abstractmethod
from copy import deepcopy
from typing import Dict, List
class Prototype(ABC):
"""原型抽象类,声明克隆方法"""
@abstractmethod
def clone(self):
"""克隆自身
Returns:
Prototype: 克隆后的对象
"""
pass
class ConcretePrototype1(Prototype):
"""具体原型类1"""
def __init__(self, id: str, name: str, data: List[str] = None):
"""初始化原型
Args:
id: 对象ID
name: 对象名称
data: 数据列表
"""
self.id = id
self.name = name
self.data = data or []
def clone(self):
"""深克隆实现"""
# 使用deepcopy确保复杂对象的完全复制
return deepcopy(self)
def __str__(self) -> str:
return f"ConcretePrototype1(id={self.id}, name={self.name}, data={self.data})"
class ConcretePrototype2(Prototype):
"""具体原型类2"""
def __init__(self, id: str, config: Dict, metadata: str = ""):
"""初始化原型
Args:
id: 对象ID
config: 配置字典
metadata: 元数据
"""
self.id = id
self.config = config
self.metadata = metadata
def clone(self):
"""深克隆实现"""
return deepcopy(self)
def __str__(self) -> str:
return f"ConcretePrototype2(id={self.id}, config={self.config}, metadata={self.metadata})"
class PrototypeRegistry:
"""原型注册表,存储和管理原型实例"""
def __init__(self):
self._prototypes: Dict[str, Prototype] = {}
def register_prototype(self, name: str, prototype: Prototype) -> None:
"""注册原型
Args:
name: 原型名称
prototype: 原型实例
"""
self._prototypes[name] = prototype
def unregister_prototype(self, name: str) -> None:
"""注销原型
Args:
name: 原型名称
"""
if name in self._prototypes:
del self._prototypes[name]
def clone(self, name: str) -> Prototype:
"""克隆指定名称的原型
Args:
name: 原型名称
Returns:
Prototype: 克隆后的对象
Raises:
ValueError: 当原型不存在时
"""
prototype = self._prototypes.get(name)
if not prototype:
raise ValueError(f"未找到名为'{name}'的原型")
return prototype.clone()
# 扩展:实现浅克隆和深克隆
class ShallowAndDeepCloneExample:
"""演示浅克隆和深克隆的区别"""
class Person:
"""人类,包含基本信息和引用类型成员"""
def __init__(self, name: str, age: int, address: Dict):
"""初始化
Args:
name: 姓名
age: 年龄
address: 地址字典
"""
self.name = name
self.age = age
self.address = address # 引用类型成员
def shallow_clone(self) -> 'ShallowAndDeepCloneExample.Person':
"""浅克隆
Returns:
Person: 克隆后的对象
"""
import copy
return copy.copy(self) # 浅复制
def deep_clone(self) -> 'ShallowAndDeepCloneExample.Person':
"""深克隆
Returns:
Person: 克隆后的对象
"""
import copy
return copy.deepcopy(self) # 深复制
def __str__(self) -> str:
return f"Person(name={self.name}, age={self.age}, address={self.address})"
# 实际应用示例:文档模板系统
class DocumentTemplate(Prototype):
"""文档模板类"""
def __init__(self, title: str, content: str, author: str = "", metadata: Dict = None):
"""初始化文档模板
Args:
title: 文档标题
content: 文档内容
author: 作者
metadata: 元数据(如格式、创建日期等)
"""
self.title = title
self.content = content
self.author = author
self.metadata = metadata or {}
def clone(self):
"""克隆文档模板"""
return deepcopy(self)
def fill_template(self, **kwargs) -> 'DocumentTemplate':
"""填充模板中的变量
Args:
**kwargs: 要替换的变量键值对
Returns:
DocumentTemplate: 填充后的文档
"""
result = self.clone()
for key, value in kwargs.items():
placeholder = f"{{{{ {key} }}}}"
result.title = result.title.replace(placeholder, str(value))
result.content = result.content.replace(placeholder, str(value))
return result
def __str__(self) -> str:
return f"DocumentTemplate(title='{self.title}', author='{self.author}', metadata={self.metadata})"
class DocumentManager:
"""文档管理器,使用原型模式管理文档模板"""
def __init__(self):
self.template_registry = PrototypeRegistry()
self._setup_default_templates()
def _setup_default_templates(self) -> None:
"""设置默认模板"""
# 创建报告模板
report_template = DocumentTemplate(
title="{{ company_name }} 季度报告",
content="# {{ company_name }} 季度报告\n\n" +
"## 执行摘要\n{{ summary }}\n\n" +
"## 财务数据\n{{ financial_data }}\n\n" +
"## 展望\n{{ outlook }}",
metadata={"type": "report", "version": "1.0"}
)
# 创建邮件模板
email_template = DocumentTemplate(
title="关于{{ subject }}的通知",
content="尊敬的{{ recipient }}\n\n" +
"{{ message_body }}\n\n" +
"此致,\n{{ sender }}",
metadata={"type": "email", "version": "1.0"}
)
# 创建合同模板
contract_template = DocumentTemplate(
title="{{ client_name }} 服务合同",
content="# 服务合同\n\n" +
"甲方:{{ company_name }}\n" +
"乙方:{{ client_name }}\n\n" +
"## 服务内容\n{{ service_description }}\n\n" +
"## 费用\n{{ payment_terms }}",
metadata={"type": "contract", "version": "1.0"}
)
# 注册模板
self.template_registry.register_prototype("report", report_template)
self.template_registry.register_prototype("email", email_template)
self.template_registry.register_prototype("contract", contract_template)
def create_document(self, template_name: str, **kwargs) -> DocumentTemplate:
"""创建文档
Args:
template_name: 模板名称
**kwargs: 模板填充参数
Returns:
DocumentTemplate: 创建的文档
"""
template = self.template_registry.clone(template_name)
return template.fill_template(**kwargs)
def main():
"""演示原型模式"""
print("=== 原型模式演示 ===")
# 基本原型模式演示
print("\n1. 基本原型模式:")
prototype1 = ConcretePrototype1("001", "原型1", ["数据1", "数据2"])
prototype2 = ConcretePrototype2("002", {"key1": "value1", "key2": "value2"}, "元数据")
# 克隆
clone1 = prototype1.clone()
clone2 = prototype2.clone()
print(f"原始原型1: {prototype1}")
print(f"克隆后的原型1: {clone1}")
print(f"是否同一个对象: {prototype1 is clone1}") # 应该是False
print(f"\n原始原型2: {prototype2}")
print(f"克隆后的原型2: {clone2}")
print(f"是否同一个对象: {prototype2 is clone2}") # 应该是False
# 修改克隆对象,验证是否是深克隆
clone1.data.append("新数据")
clone2.config["key3"] = "value3"
print(f"\n修改后的克隆1: {clone1}")
print(f"原始原型1(不应受影响): {prototype1}")
print(f"\n修改后的克隆2: {clone2}")
print(f"原始原型2(不应受影响): {prototype2}")
# 原型注册表演示
print("\n2. 原型注册表:")
registry = PrototypeRegistry()
registry.register_prototype("prototype1", prototype1)
registry.register_prototype("prototype2", prototype2)
try:
# 从注册表克隆
cloned_from_registry1 = registry.clone("prototype1")
cloned_from_registry2 = registry.clone("prototype2")
print(f"从注册表克隆的原型1: {cloned_from_registry1}")
print(f"从注册表克隆的原型2: {cloned_from_registry2}")
# 测试不存在的原型
registry.clone("nonexistent")
except ValueError as e:
print(f"异常处理测试: {e}")
# 浅克隆与深克隆的区别
print("\n3. 浅克隆与深克隆的区别:")
person = ShallowAndDeepCloneExample.Person(
"张三",
30,
{"city": "北京", "district": "朝阳区", "street": "建国路"}
)
# 浅克隆
shallow_clone = person.shallow_clone()
shallow_clone.name = "李四"
shallow_clone.address["city"] = "上海" # 修改引用类型
# 深克隆
deep_clone = person.deep_clone()
deep_clone.name = "王五"
deep_clone.address["city"] = "广州" # 修改引用类型
print(f"原始对象: {person}")
print(f"浅克隆对象: {shallow_clone}") # 注意原始对象的address也被修改了
print(f"深克隆对象: {deep_clone}") # 原始对象不受影响
# 文档模板系统示例
print("\n4. 文档模板系统示例:")
doc_manager = DocumentManager()
# 创建报告
report = doc_manager.create_document(
"report",
company_name="ABC公司",
summary="本季度业绩增长20%",
financial_data="营收1000万利润200万",
outlook="预计下季度继续增长"
)
print(f"\n创建的报告:\n{report}")
print(f"报告内容:\n{report.content}")
# 创建邮件
email = doc_manager.create_document(
"email",
subject="项目进度",
recipient="客户李先生",
message_body="您的项目已完成80%,预计下周交付。",
sender="项目经理 张工"
)
print(f"\n创建的邮件:\n{email}")
print(f"邮件内容:\n{email.content}")
if __name__ == "__main__":
main()