Python设计模式 - 原型模式

定义

原型模式是一种创建型设计模式,它可以通过复制现有对象来创建新对象,而不是直接实例化新的对象。

结构

  • 抽象原型(Prototype):声明 clone() 方法,以便派生类实现克隆自身的能力。
  • 具体原型(Concrete Prototype):实现抽象原型中的 clone() 方法,需要考虑是浅拷贝还是深拷贝
  • 客户端(Client):使用 clone() 方法创建新对象。

应用场景

  1. 创建成本高且需要重复创建对象:当对象的创建过程较为昂贵(如涉及数据库查询、复杂计算或大量I/O操作),可以使用原型模式来避免重复创建,从而提升性能。例如,游戏角色的存档加载、图像处理中的大文件复制等。
  2. 需要保存对象的历史状态或备份:在需要支持撤销(Undo)或快照(Snapshot)功能的场景下,可以使用原型模式存储对象的状态,并在需要时恢复。例如,文档编辑器的撤销功能、数据库事务回滚等。
  3. 系统需要减少子类的数量:通过使用原型模式,系统可以避免为每种配置创建新的子类,而是通过克隆已有对象并进行修改来生成新实例,从而减少类的数量。例如,配置文件的动态加载、不同软件版本的实例化等。

优缺点

优点:

  1. 简化类层次结构:通过克隆创建对象,而不是通过继承创建子类,从而减少子类数量。
  2. 提高对象创建效率:直接克隆已有对象,而不是重新构造,能显著提升性能。

缺点:

  1. 违背开闭原则:每个具体原型类需要实现克隆方法,而且该克隆方法位于类的内部。当对已有的类进行改造时,需要修改源代码,违背了开闭原则。
  2. 实现深拷贝较为复杂:在实现深拷贝时需要编写较为复杂的代码,特别是当对象之间存在多重的嵌套引用时,为了实现深拷贝,每一层对象对应的类都必须支持深拷贝。

代码示例

浅拷贝

浅拷贝只复制对象的第一层(即顶层对象),并不会递归地复制嵌套在对象内部的可变对象(如列表、字典、集合等)。

python 复制代码
import copy
from abc import ABC, abstractmethod


# 抽象原型类
class Prototype(ABC):
    @abstractmethod
    def clone(self):
        pass


# 具体原型类(Car)
class Car(Prototype):
    def __init__(self, brand, model, color):
        self.brand = brand
        self.model = model
        self.color = color

    def __str__(self):
        return f"{self.color} {self.brand} {self.model}"

    def clone(self, **attrs):
        """克隆对象,并允许修改部分属性"""
        # 创建浅拷贝
        cloned_obj = copy.copy(self)
        # 更新克隆对象的属性
        cloned_obj.__dict__.update(attrs)
        return cloned_obj


# 创建原型对象
car1 = Car("Tesla", "Model S", "Red")

# 克隆对象,并修改颜色
car2 = car1.clone(color="Blue")

print(car1)  # 输出: Red Tesla Model S
print(car2)  # 输出: Blue Tesla Model S

深拷贝

深拷贝会递归地复制对象及其所有嵌套的可变对象,创建一个完全独立的新对象。

深拷贝的代码只需要在浅拷贝代码的基础上把copy.copy(self)改成copy.deepcopy(self)即可。

python 复制代码
# 具体原型类(Car)
class Car(Prototype):
    def __init__(self, brand, model, color, features):
        self.brand = brand
        self.model = model
        self.color = color
        self.features = features  # 可变对象(如列表)

    def __str__(self):
        return f"{self.color} {self.brand} {self.model}"

    def clone(self, **attrs):
        """深拷贝对象,并允许修改部分属性"""
        # 创建深拷贝
        cloned_obj = copy.deepcopy(self)
        # 更新克隆对象的属性
        cloned_obj.__dict__.update(attrs)
        return cloned_obj


# 创建原型对象
car1 = Car("Tesla", "Model S", "Red", ["Autopilot", "Glass Roof"])

# 克隆对象,并修改颜色
car2 = car1.clone(color="Blue")

# 修改 car2 的 features
car2.features.append("Self-driving")

# 查看 car1 和 car2 的内容
print("car1:", car1)  # 输出: Red Tesla Model S
print("car2:", car2)  # 输出: Blue Tesla Model S
print("car1.features:", car1.features)  # 输出: ['Autopilot', 'Glass Roof']
print("car2.features:", car2.features)  # 输出: ['Autopilot', 'Glass Roof', 'Self-driving']

原型管理器

原型管理器用于管理和存储原型对象,它存储系统中常用的原型对象,并为客户端提供访问和拷贝这些原型对象的接口,能够减少重复创建原型对象的工作。

下面为深拷贝代码示例增加原型管理器:

python 复制代码
# 原型管理器
class PrototypeManager:
    def __init__(self):
        self._prototypes = {}

    def register(self, name, obj):
        """注册原型对象"""
        self._prototypes[name] = obj

    def unregister(self, name):
        """移除原型对象"""
        if name in self._prototypes:
            del self._prototypes[name]

    def clone(self, name, **attrs):
        """克隆对象,并可修改部分属性"""
        if name not in self._prototypes:
            raise ValueError(f"原型 '{name}' 未注册")
        return self._prototypes[name].clone(**attrs)


# 创建原型管理器
prototype_manager = PrototypeManager()

# 创建一个Car实例,并注册到原型管理器
car1 = Car("Tesla", "Model S", "Red", ["Autopilot", "Glass Roof"])
prototype_manager.register("electric_car", car1)

# 克隆对象,并修改颜色
car2 = prototype_manager.clone("electric_car", color="Blue")

print(car1)  # 输出: Red Tesla Model S
print(car2)  # 输出: Blue Tesla Model S

# 取消注册某个原型
prototype_manager.unregister("electric_car")

# 再次尝试克隆(会抛出异常)
try:
    car3 = prototype_manager.clone("electric_car")
except ValueError as e:
    print(e)  # 输出: 原型 'electric_car' 未注册

参考

《设计模式的艺术》

相关推荐
ytusdc5 分钟前
pycharm配置anaconda环境时找不到python.exe解决办法
ide·python·pycharm
I'mAlex5 分钟前
【Python】一文讲透Pygame教程,非常详细
开发语言·python·pygame
轩辰q6 分钟前
正则表达式(python版最全面,最易懂)
开发语言·python
一见已难忘7 分钟前
Flask与FastAPI对比选择最佳Python Web框架的指南
python·flask·fastapi
椰椰椰耶13 分钟前
【Python】文件操作
开发语言·python
shanks6614 分钟前
【PyQt】keyPressEvent键盘按压事件无响应
开发语言·python·pyqt
醒醒a14 分钟前
windows下安装Open Web UI
python
张同学的IT技术日记15 分钟前
线性代数于工程应用中的实践:以代码实例拆解相似性度量问题的求解逻辑
开发语言·笔记·python·学习·线性代数·工程应用
张同学的IT技术日记15 分钟前
线性代数于工程应用中的实践:以代码实例拆解图像平滑问题的求解逻辑
开发语言·笔记·python·学习·线性代数·工程应用
小田_27 分钟前
UV - Python 包管理
开发语言·python·uv