当前位置: 首页 > news >正文

【设计模式】深入理解Python中的原型设计模式

深入理解Python中的原型设计模式

在软件开发中,有时需要创建对象的过程非常复杂或者代价较高,而在同一类对象的实例之间有很多重复的属性。为了避免重复构造对象,提升性能和效率,原型设计模式(Prototype Pattern)应运而生。

原型模式是一种创建型设计模式,它允许我们通过复制现有对象来创建新的对象,而不是通过实例化类创建对象。这样不仅可以简化对象的创建过程,还能显著提高性能。

在这篇文章中,我们将全面深入探讨原型模式的定义、使用场景、Python实现方法及其优缺点。

1. 什么是原型设计模式?

原型设计模式的核心思想是:通过复制现有对象来创建新的对象。原型模式在某种程度上是一种浅拷贝或深拷贝技术,通过复制一个对象的所有属性而无需重新执行构造函数。

原型模式的核心角色

  1. 原型接口(Prototype Interface):定义一个可以克隆自身的接口,通常是通过 clone() 方法来复制对象。
  2. 具体原型类(Concrete Prototype):实现 clone() 方法,允许克隆自身。
  3. 客户端(Client):通过调用原型对象的 clone() 方法来复制对象。

原型模式的UML表示

+-----------------+
|  Prototype      |
+-----------------+
|  + clone()      |
+-----------------+▲|
+-----------------+
| ConcretePrototype|
+-----------------+
|  + clone()      |
+-----------------+
  • Prototype:定义了clone()方法,用于复制对象。
  • ConcretePrototype:具体原型类实现了clone()方法,可以生成自身的拷贝。
  • Client:客户端通过原型对象进行对象复制。

2. 原型模式的应用场景

原型模式适用于以下场景:

  1. 对象的创建成本高:当对象的创建代价昂贵,且对象构造过程非常复杂时,使用原型模式可以通过复制现有对象快速生成新的实例。
  2. 需要创建多个相似的对象:如果多个对象的结构相似,使用原型模式可以通过复制来创建多个相似的实例,而无需手动创建或配置每个实例。
  3. 需要避免依赖具体类:通过原型模式,客户端无需依赖具体类来创建对象,降低了耦合度。
  4. 实例化需要动态变化:在某些场景下,对象的结构和配置会动态改变,原型模式可以帮助通过复制动态生成具有不同配置的对象。

典型的应用场景

  • 对象池(Object Pool):为了提高性能,很多系统会维护对象池,使用原型模式复制对象池中的现有对象来减少实例化开销。
  • 游戏开发:在游戏中,有许多相似的角色、怪物或道具,使用原型模式可以快速生成这些对象。
  • 配置管理:在需要不同配置但具有相似结构的系统中,可以通过原型模式快速复制并生成配置文件。

3. Python中的原型模式实现

3.1 原型接口与实现

在Python中,原型模式可以通过 copy 模块中的 copy()deepcopy() 函数实现。Python中的拷贝分为浅拷贝和深拷贝,分别对对象的引用和实际值进行拷贝。

浅拷贝与深拷贝的区别
  • 浅拷贝:创建一个新的对象,但不复制嵌套对象的内容。对原始对象中嵌套对象的修改会反映在拷贝对象中。
  • 深拷贝:递归复制所有嵌套对象,创建一个完全独立的副本。

首先,我们定义一个Prototype类,使用clone()方法来实现对象的复制。

import copy
from abc import ABC, abstractmethod# 抽象原型类
class Prototype(ABC):@abstractmethoddef clone(self):pass

3.2 具体原型类

接下来,我们定义具体的原型类,继承Prototype类并实现clone()方法。我们使用 copy 模块来实现浅拷贝和深拷贝。

# 具体原型类
class ConcretePrototype1(Prototype):def __init__(self, value, nested_object):self.value = valueself.nested_object = nested_objectdef clone(self, deep=False):if deep:return copy.deepcopy(self)else:return copy.copy(self)def __str__(self):return f"ConcretePrototype1(value={self.value}, nested_object={self.nested_object})"# 嵌套对象
class NestedObject:def __init__(self, attribute):self.attribute = attributedef __str__(self):return f"NestedObject(attribute={self.attribute})"

3.3 客户端代码

在客户端代码中,我们创建一个ConcretePrototype1对象,并通过浅拷贝和深拷贝的方式生成副本。

# 创建原型对象
nested_obj = NestedObject("Initial Attribute")
prototype = ConcretePrototype1(10, nested_obj)# 浅拷贝
shallow_copy = prototype.clone(deep=False)
# 深拷贝
deep_copy = prototype.clone(deep=True)# 输出原型和副本的状态
print("Original Prototype:", prototype)
print("Shallow Copy:", shallow_copy)
print("Deep Copy:", deep_copy)# 修改嵌套对象的属性
nested_obj.attribute = "Modified Attribute"print("\nAfter modifying the nested object:")
print("Original Prototype:", prototype)
print("Shallow Copy:", shallow_copy)
print("Deep Copy:", deep_copy)

运行结果:

Original Prototype: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Initial Attribute))
Shallow Copy: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Initial Attribute))
Deep Copy: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Initial Attribute))After modifying the nested object:
Original Prototype: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Modified Attribute))
Shallow Copy: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Modified Attribute))
Deep Copy: ConcretePrototype1(value=10, nested_object=NestedObject(attribute=Initial Attribute))

如上所示,在修改了嵌套对象后,浅拷贝的副本中的嵌套对象也发生了变化,而深拷贝的副本保持不变。这是因为深拷贝递归复制了所有嵌套对象,确保副本是一个完全独立的对象。

4. 原型模式的优缺点

优点

  1. 提高性能:原型模式通过复制现有对象,避免了复杂对象的重新构造,特别适合那些构造过程代价高的对象。
  2. 动态对象创建:原型模式可以动态生成对象,而不依赖于具体类,实现更灵活的对象创建机制。
  3. 减少重复代码:通过克隆现有对象,可以避免重复编写对象创建代码,简化代码逻辑。
  4. 实现对象池:原型模式是实现对象池的有效手段,在池中维护一些已有对象,随时可以复制出来使用。

缺点

  1. 对象拷贝的复杂性:对于包含复杂结构或深层嵌套的对象,特别是有引用循环的对象,拷贝的实现可能会变得复杂,可能需要额外的处理来防止深拷贝出现性能问题。
  2. 潜在的对象状态问题:在一些情况下,复制对象可能会导致共享状态问题,特别是在浅拷贝时,多个对象可能会共享相同的引用,修改其中一个会影响其他对象。

5. 原型模式的改进

在Python中,由于语言的动态特性,我们可以通过定制__copy__()__deepcopy__()方法,优化对象的拷贝行为。对于复杂对象结构,可以选择性地实现浅拷贝和深拷贝。

自定义 __copy__()__deepcopy__()

class CustomPrototype:def __init__(self, name, data):self.name = nameself.data = datadef __copy__(self):print("Performing shallow copy")return CustomPrototype(self.name, self.data)def __deepcopy__(self, memo):print("Performing deep copy")new_data = copy.deepcopy(self.data, memo)return CustomPrototype(self.name, new_data)# 测试自定义拷贝行为
prototype = CustomPrototype("Original", {"key": "value"})
shallow = copy.copy(prototype)
deep = copy.deepcopy(prototype)

在自定义 __copy__()__deepcopy__() 方法时,我们可以精细控制哪些部分需要拷贝,哪些部分保持引用。这种方式可以在提高性能的同时避免冗余操作。

6. 结论

原型模式是一种灵活且高效的设计模式,通过复制现有对象来创建新的对象,从而避免了复杂的对象构造过程。在Python中,利用其内置的 copy 模块,我们可以轻松实现浅拷贝和深拷贝的功能。

原型模式尤其适合需要创建大量相似对象的场景,如对象池、游戏开发和配置管理。虽然它可以提高性能和减少重复代码,但在使用时需要特别注意对象拷贝的深度问题,以避免共享状态引发的潜在问题。

通过本文的介绍,希望你能够对原型模式的定义、应用场景和Python中的实现有一个全面的理解,并能够在实际项目中灵活应用这一模式。

相关文章:

【设计模式】深入理解Python中的原型设计模式

深入理解Python中的原型设计模式 在软件开发中,有时需要创建对象的过程非常复杂或者代价较高,而在同一类对象的实例之间有很多重复的属性。为了避免重复构造对象,提升性能和效率,原型设计模式(Prototype Pattern&…...

Django CORS配置方案

参考 https://pypi.org/project/django-cors-headers/ 在setting.py中设置 INSTALLED_APPS [......corsheaders, #添加此行 ]MIDDLEWARE[......corsheaders.middleware.CorsMiddleware, #添加此行django.middleware.common.CommonMiddleware,#django.middleware.csrf.CsrfVi…...

2024年开放式耳机哪个牌子好?推荐最好的顶级开放式耳机品牌

在当下,开放式耳机逐渐成为众多消费者的新宠。与传统入耳式耳机相比,开放式耳机展现出诸多独特之处。它可以呈现出更清晰的音质效果,让用户有更美妙的听觉体验。在佩戴感上,开放式耳机更为舒适,不会给耳朵带来压迫感。…...

零基础读懂Stable Diffusion!

前言 一文搞懂Stable Diffusion是什么,怎么训练和使用,语义信息影响生成图片的过程。>>[][加入极市CV技术交流群,走在计算机视觉的最前沿] 前几个月AIGC可谓是大热了一把,各种高质量的生成图片层出不穷,而其中…...

Hash Join 和 Index Join工作原理和性能差异

在数据库查询中,Hash Join 和 Index Join 是两种常见的表连接策略。了解它们的工作原理和性能差异有助于设计高效的数据库查询。我们可以使用 Java 模拟这两种不同的连接方式,并进行性能对比。 1. Hash Join 和 Index Join 的概念: Hash Joi…...

Apifox简介及使用

Apifox 是一款集 API文档管理、接口调试、接口自动化测试 和 Mock 功能于一体的全功能工具,旨在为开发者和测试人员提供一个高效的一站式解决方案。它融合了 Postman、Swagger、JMeter 等工具的优势,能够极大地提升团队协作和 API 开发的效率。 在实际开…...

十、IPD 实施细节(产品设计与开发管理)

产品设计与开发管理 产品设计与开发管理是IPD(集成产品开发)实施过程中的核心环节。它确保从概念设计到最终产品的实现能够按照预定的质量、成本、进度目标顺利完成,并与市场需求、技术发展及企业战略保持一致。IPD强调产品设计与开发管理过程中跨职能团队的协作、流程的系…...

MySQL-13.DQL-聚合函数

一.DQL-分组查询 二.聚合函数 -- DQL:分组查询 -- 聚合函数 -- 1.统计该企业员工数量 count select count(id) from tb_emp; select count(job) from tb_emp;select count(A) from tb_emp; select count(*) from tb_emp;-- 2.统计该企业最早入职的员工 min select min(entr…...

为什么跟别人学习如何证明定理要远比使用定理更有意义

目录 背景 为什么跟别人学习 什么是高人,如何判断 高人定义 如何判断一个人的能力? 如何考量一个人的成就? 只知道使用定理的局限性 1. 缺乏灵活性和适应性 2. 无法创新或拓展新方法 3. 容易误用或误解定理 4. 难以推理和分析复杂问…...

Qt在Win,Mac和Linux的开机自启设置

Windows Windows 使用注册表来管理开机自启的应用程序。 void runWithSystem(const QString& name, const QString& path, bool autoRun) {QSetting reg("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSetting::NativeForma…...

spring boot热部署

使用热部署解决了每次都需要重新启动的问题&#xff0c;但不过热部署的在对于改动比较小时速度可能快一些&#xff0c;改动大的话尽量停止 1.使用热部署之前需要在pom.xml文件中导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifa…...

网关与蓝牙网关有什么不同之处?

尽管蓝牙网关也属于网关的一种&#xff0c;但在实际应用和功能特性上&#xff0c;它们之间存在着显著的差异。接下来&#xff0c;我们将深入探讨蓝牙网关的独特之处&#xff0c;并与传统网关进行对比分析。 一、网关与蓝牙网关的共同之处 一对多配对能力&#xff1a;无论是网关…...

JAVA计算双十一多产品实付款优惠券的省钱方案

为了计算双十一期间多产品使用优惠券后的实付款省钱方案&#xff0c;我们需要一个更复杂的逻辑来处理优惠券的应用和叠加规则。以下是一个简化的Java示例&#xff0c;用于展示如何计算多种优惠券应用于多个产品后的实付款金额&#xff0c;并找出最省钱的方案。 首先&#xff0…...

零售行业的数字化营销转型之路

一方面&#xff0c;市场竞争激烈&#xff0c;电商平台、新兴品牌和跨界对手带来巨大压力。另一方面&#xff0c;消费者需求变化迅速&#xff0c;更加追求个性化、多元化和便捷化的购物体验&#xff0c;同时传统零售企业还面临着高成本压力&#xff0c;如租金、人力和库存等。 然…...

js的for in 和 for of的详解

for...in 和 for...of 是 JavaScript 中的两种循环结构&#xff0c;它们用于不同的场景&#xff0c;适用于不同的数据类型。下面将详细介绍它们的用法、区别以及适用场景。 1. for...in 循环 for...in 用于遍历对象的可枚举属性&#xff08;包括继承的属性&#xff09;。 语…...

前端工具函数库

流行的前端工具函数库 lodashlodash-es&#xff1a;用lodash-es代替lodashes-toolkit&#xff1a;https://www.npmjs.com/package/es-toolkitradash&#xff1a;https://github.com/sodiray/radash 补充信息&#xff1a; antd-mobile 已不再依赖 lodash&#xff0c; 淘汰 lo…...

Java程序设计:Spring boot(4)——Freemarker Thymeleaf视图技术集成

1 Freemarker 视图集成 SpringBoot 内部⽀持 Freemarker 视图技术的集成&#xff0c;并提供了⾃动化配置类 FreeMarkerAuto Configuration&#xff0c;借助⾃动化配置可以很⽅便的集成 Freemarker基础到 SpringBoot 环境中。这⾥借助⼊⻔项⽬引⼊ Freemarker 环境配置。 Start…...

JavaScript 第19章:Web Storage

在JavaScript中&#xff0c;Web存储&#xff08;Web Storage&#xff09;提供了一种在用户浏览器中持久化数据的方式。这里我们会探讨localStorage、sessionStorage以及IndexedDB&#xff0c;并提供一些简单的示例代码来展示它们的用法。 localStorage localStorage允许你在用…...

[山河2024] week2

官方WP出得很快。对照官的写下私的。大概出入不大&#xff0c;毕竟第2周。后边的才难。 Crypto E&R RSA因子分解题&#xff0c;把q的2进制反转后与p异或。关于异或的题很多&#xff0c;这个还真是头一回见&#xff0c;不过爆破方法还是一样的。 r_q int(bin(q)[2:][::…...

无限可能LangChain——开启大模型世界

什么是大语言模型&#xff1f; 大语言模型是一种人工智能模型&#xff0c;通常使用深度学习技术&#xff08;如神经网络&#xff09;来理解和生成人类语言。这些模型拥有非常多的参数&#xff0c;可以达到数十亿甚至更多&#xff0c;使得它们能够处理高度复杂的语言模式。 我…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

JVM 内存结构 详解

内存结构 运行时数据区&#xff1a; Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器&#xff1a; ​ 线程私有&#xff0c;程序控制流的指示器&#xff0c;分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 ​ 每个线程都有一个程序计数…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障

关键领域软件测试的"安全密码"&#xff1a;Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力&#xff0c;从金融交易到交通管控&#xff0c;这些关乎国计民生的关键领域…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅

目录 前言 操作系统与驱动程序 是什么&#xff0c;为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中&#xff0c;我们在使用电子设备时&#xff0c;我们所输入执行的每一条指令最终大多都会作用到硬件上&#xff0c;比如下载一款软件最终会下载到硬盘上&am…...