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

- 抽象原型(Prototype):声明 clone() 方法,以便派生类实现克隆自身的能力。
- 具体原型(Concrete Prototype):实现抽象原型中的 clone() 方法,需要考虑是浅拷贝还是深拷贝。
- 客户端(Client):使用 clone() 方法创建新对象。
应用场景
- 创建成本高且需要重复创建对象:当对象的创建过程较为昂贵(如涉及数据库查询、复杂计算或大量I/O操作),可以使用原型模式来避免重复创建,从而提升性能。例如,游戏角色的存档加载、图像处理中的大文件复制等。
- 需要保存对象的历史状态或备份:在需要支持撤销(Undo)或快照(Snapshot)功能的场景下,可以使用原型模式存储对象的状态,并在需要时恢复。例如,文档编辑器的撤销功能、数据库事务回滚等。
- 系统需要减少子类的数量:通过使用原型模式,系统可以避免为每种配置创建新的子类,而是通过克隆已有对象并进行修改来生成新实例,从而减少类的数量。例如,配置文件的动态加载、不同软件版本的实例化等。
优缺点
优点:
- 简化类层次结构:通过克隆创建对象,而不是通过继承创建子类,从而减少子类数量。
- 提高对象创建效率:直接克隆已有对象,而不是重新构造,能显著提升性能。
缺点:
- 违背开闭原则:每个具体原型类需要实现克隆方法,而且该克隆方法位于类的内部。当对已有的类进行改造时,需要修改源代码,违背了开闭原则。
- 实现深拷贝较为复杂:在实现深拷贝时需要编写较为复杂的代码,特别是当对象之间存在多重的嵌套引用时,为了实现深拷贝,每一层对象对应的类都必须支持深拷贝。
代码示例
浅拷贝
浅拷贝只复制对象的第一层(即顶层对象),并不会递归地复制嵌套在对象内部的可变对象(如列表、字典、集合等)。
import copy
from abc import ABC, abstractmethod# 抽象原型类
class Prototype(ABC):@abstractmethoddef clone(self):pass# 具体原型类(Car)
class Car(Prototype):def __init__(self, brand, model, color):self.brand = brandself.model = modelself.color = colordef __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)即可。
# 具体原型类(Car)
class Car(Prototype):def __init__(self, brand, model, color, features):self.brand = brandself.model = modelself.color = colorself.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']
原型管理器
原型管理器用于管理和存储原型对象,它存储系统中常用的原型对象,并为客户端提供访问和拷贝这些原型对象的接口,能够减少重复创建原型对象的工作。
下面为深拷贝代码示例增加原型管理器:
# 原型管理器
class PrototypeManager:def __init__(self):self._prototypes = {}def register(self, name, obj):"""注册原型对象"""self._prototypes[name] = objdef 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' 未注册
参考
《设计模式的艺术》
相关文章:
Python设计模式 - 原型模式
定义 原型模式是一种创建型设计模式,它可以通过复制现有对象来创建新对象,而不是直接实例化新的对象。 结构 抽象原型(Prototype):声明 clone() 方法,以便派生类实现克隆自身的能力。具体原型(…...
金和OA C6 DownLoadBgImage任意文件读取漏洞
金和OA C6 DownLoadBgImage任意文件读取漏洞 漏洞描述 金和C6数据库是一款针对企业信息化管理而设计的高级数据库管理系统,主要应用于企业资源规划(ERP)、客户关系管理(CRM)以及办公自动化(OA)…...
【stm32学习】STM32F103实操primary(FlyMCU)
github插入图片实在是太难用了,暂时懒得学就先用CSDN吧hh 一、在设备管理器下,找到单片机,并检查与FlyMCU-搜索端口 显示的是否一致 二、在搜索串口右面的栏里选中该Port,波特率选中115200 三、选择文件夹中的.hex文件࿰…...
如何将Excel的表格存为图片?
emmm,不知道题主具体的应用场景是什么,就分享几个我一般会用到的场景下奖excel表格保存为图片的技巧吧! 先来个总结: 方法 适用场景 画质 操作难度 截图(WinShiftS) 快速保存表格,方便粘贴…...
51单片机之使用Keil uVision5创建工程以及使用stc-isp进行程序烧录步骤
一、Keil uVision5创建工程步骤 1.点击项目,新建 2.新建目录 3.选择目标机器,直接搜索at89c52选择,然后点击OK 4.是否添加起吊文件,一般选择否 5.再新建的项目工程中添加文件 6.选择C文件 7.在C文件中右键,添加…...
AUTOSAR面试题集锦(1)
最基础概念 什么是AUTOSAR?AUTOSAR到底做了什么? AUTOSAR,即汽车开放系统架构,是一套专门用于汽车的开放性的框架和行业标准,旨在标准化汽车开发的流程。 AUTOSAR 通过标准化软件接口、交换格式和方法论等内容,主要实现以下几个目标: 1. 使软件和硬件彼此独立,让应…...
【Uniapp-Vue3】从uniCloud中获取数据
需要先获取数据库对象: let db uniCloud.database(); 获取数据库中数据的方法: db.collection("数据表名称").get(); 所以就可以得到下面的这个模板: let 函数名 async () > { let res await db.collection("数据表名称…...
AIOS: 一个大模型驱动的Multi-Agent操作系统设计与Code分析
AIOS: 一个大模型驱动的Multi-Agent操作系统设计与Code分析 随着人工智能技术的快速发展,传统操作系统逐渐暴露出难以适应AI时代多样化需求的局限性。特别是在支持多个智能体协同工作方面存在显著不足。为此,我们提出了一种名为AIOS(Artifici…...
Python----Python高级(网络编程:网络基础:发展历程,IP地址,MAC地址,域名,端口,子网掩码,网关,URL,DHCP,交换机)
一、网络 早期的计算机程序都是在本机上运行的,数据存储和处理都在同一台机器上完成。随着技术的发展,人 们开始有了让计算机之间相互通信的需求。例如安装在个人计算机上的计算器或记事本应用,其运行环 境仅限于个人计算机内部。这种设置虽然…...
收集的面试资料
转载自:NLP_基于酒店评论的情感分析-CSDN博客 机器学习的一般过程 如何介绍项目: 项目背景:项目输入,输出,后续应用点 项目数据:数据来源 数据处理方法:是否有脏数据,如何处理脏数据…...
pytest-xdist 进行多进程并发测试!
在软件开发过程中,测试是确保代码质量和可靠性的关键步骤。随着项目规模的扩大和复杂性的增加,测试用例的执行效率变得尤为重要。为了加速测试过程,特别是对于一些可以并行执行的测试用 例,pytest-xdist 提供了一种强大的工具&…...
LVGL4种输入设备详解(触摸、键盘、实体按键、编码器)
lvgl有触摸、键盘、实体按键、编码器四种输入设备 先来分析一下这四种输入设备有什么区别 (1)LV_INDEV_TYPE_POINTER 主要用于触摸屏 用到哪个输入设备保留哪个其他的也是,保留触摸屏输入的任务注册,其它几种种输入任务的注册&…...
全流程安装DeepSeek开源模型
目录 配置要求安装Ollama选择大模型安装大模型对话备注 配置要求 我的电脑配置为: CPU:i7 12代 GPU:3080 内存:32g 磁盘:1T以上配置运行情况: 运行ollama run deepseek-r1:7b模型无压力,CPU/…...
人工智能领域-CNN 卷积神经网络 性能调优
在自动驾驶领域,对卷积神经网络(CNN)进行性能调优至关重要,以下从数据处理、模型架构、训练过程、超参数调整和模型部署优化等多个方面为你详细介绍调优方法,并给出相应的代码示例。 1. 数据处理 数据增强࿱…...
人工智能A*算法与CNN结合- CNN 增加卷积层的数量,并对卷积核大小进行调整
以下是一个增强版的将 A* 算法与卷积神经网络(CNN)结合的代码实现,其中 CNN 增加了卷积层的数量,并对卷积核大小进行了调整。整体思路依然是先利用 A* 算法生成训练数据,再用这些数据训练 CNN 模型,最后使用…...
机器学习中常用的评价指标
一、分类任务常用指标 1. 准确率(Accuracy) 定义:正确预测样本数占总样本数的比例。优点:直观易懂,适用于类别平衡的数据。缺点:对类别不平衡数据敏感(如欺诈检测中99%的负样本)。…...
Windows安装cwgo,一直安装的是linux平台的
Windows安装cwgo,一直安装的是linux平台的 查看 go env ,发现 GOOSlinux 临时修改 GOOS ,set GOOSwindows ,再安装。 此时,安装的就是 windows 的可执行文件。安装之后再将 GOOS 修改回来即可。...
GitHub Pages + Jekyll 博客搭建指南(静态网站)
目录 🚀 静态网站及其生成工具指南🌍 什么是静态网站?📌 静态网站的优势⚖️ 静态网站 VS 动态网站 🚀 常见的静态网站生成器对比🛠️ 使用 GitHub Pages Jekyll 搭建个人博客📌 1. 创建 GitHu…...
21.[前端开发]Day21-HTML5新增内容-CSS函数-BFC-媒体查询
王者荣耀-网页缩小的问题处理 为什么会产生这个问题?怎么去解决 可以给body设置最小宽度 1 HTML5新增元素 HTML5语义化元素 HTML5其他新增元素 2 Video、Audio元素 HTML5新增元素 - video video支持的视频格式 video的兼容性写法 HTML5新增元素 - audio audio…...
C++SLT(五)——list
目录 一、list的介绍二、list的使用list的定义方式 三、list的插入和删除push_back和pop_backpush_front和pop_frontinserterase 四、list的迭代器使用五、list的元素获取六、list的大小控制七、list的操作函数sort和reversemergeremoveremove_ifuniqueassignswap 一、list的介…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
高防服务器能够抵御哪些网络攻击呢?
高防服务器作为一种有着高度防御能力的服务器,可以帮助网站应对分布式拒绝服务攻击,有效识别和清理一些恶意的网络流量,为用户提供安全且稳定的网络环境,那么,高防服务器一般都可以抵御哪些网络攻击呢?下面…...
