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

创建型设计模式-原型模式(prototype)- python实现

设计模式汇总:查看

通俗示例

想象一下,你正在制作一个复杂的文档,这个文档包含了大量的文本、图片和格式设置。现在,你希望创建一个与当前文档内容完全相同的新文档,但又不希望花费时间重新编辑和排版。在这个时候,如果有一个“复制”按钮,你可以一键复制整个文档,并在新的副本上进行修改,这该多方便啊!这个“复制”按钮就是原型模式的现实例子。

通俗解释

原型模式是一种创建型设计模式,它允许我们通过复制现有的对象来创建新的对象,而不是通过传统的构造函数创建。这种模式特别适用于创建复杂对象时,可以避免初始化的复杂性,提高效率。

在原型模式中,我们有一个原型接口,它定义了复制自身的方法。具体原型类会实现这个接口,并提供复制自身的具体逻辑。当客户端需要创建一个新对象时,它不是直接实例化一个新对象,而是向一个原型对象请求一个复制自身的方法,从而获得一个新的对象。

原型模式的组成

  • 抽象原型(Prototype):这是一个接口,用来声明复制自身的方法。
  • 具体原型(Concrete Prototype):实现了抽象原型的接口,提供复制自身的具体实现。
  • 客户端(Client):通过调用原型对象的复制方法来创建新的对象。

原型模式的两种复制方式

  • 浅复制:只复制对象本身及其包含的值类型的成员变量,而对于引用类型的成员变量,浅复制会复制引用,不会复制引用指向的对象。
  • 深复制:除了复制对象本身及其包含的值类型的成员变量外,还会复制引用类型的成员变量所指向的对象。

Python代码示例

下面是一个简单的原型模式实现示例

"""
比如:当我们出版了一本书《Python 设计模式 1.0版》,
若10 年后我们觉得这本书跟不上时代了,这时候需要去重写一本《Python 设计模式 2.0版》,
那么我们是完全重写一本书呢?还是在原有《Python 设计模式 1.0版》的基础上进行修改呢?
当然是后者,这样会省去很多排版、添加原有知识等已经做过的工作。
"""
import copy
from collections import OrderedDictclass Book:def __init__(self, name, authors, price, **rest):"""rest的例子有:出版商、长度、标签、出版日期"""self.name = nameself.authors = authorsself.price = priceself.__dict__.update(rest)      # 添加其他额外属性def __str__(self):mylist = []ordered = OrderedDict(sorted(self.__dict__.items()))for i in ordered.keys():mylist.append('{}: {}'.format(i, ordered[i]))if i == 'price':mylist.append('$')mylist.append('\n')return ''.join(mylist)class Prototype:def __init__(self):self.objects = dict()    # 初始化一个原型列表def register(self, identifier, obj):# 在原型列表中注册原型对象self.objects[identifier] = objdef unregister(self, identifier):# 从原型列表中删除原型对象del self.objects[identifier]def clone(self, identifier, **attr):# 根据 identifier 在原型列表中查找原型对象并克隆found = self.objects.get(identifier)if not found:raise ValueError('Incorrect object identifier: {}'.format(identifier))obj = copy.deepcopy(found)obj.__dict__.update(attr)   # 用新的属性值替换原型对象中的对应属性return objdef main():"""主函数,用于演示克隆技术的使用。它创建了一本书的对象,并使用原型模式克隆了这本书的对象,修改了某些属性。最后,打印出两个对象的信息和它们的内存地址,以证明它们是独立的对象。"""# 创建一本书的对象,初始化各种属性,如标题、作者、价格等b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',tags=('C', 'programming', 'algorithms', 'data structures'))# 创建一个原型对象,用于后续的克隆操作prototype = Prototype()# 注册b1对象为原型,使用一个唯一标识符进行标记cid = 'k&r-first'prototype.register(cid, b1)# 使用cid克隆b1对象,并修改克隆对象的一些属性,如名称、价格、长度等b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99, length=274, publication_date='1988-04-01', edition=2)# 遍历并打印两个对象的信息for i in (b1, b2):print(i)# 打印两个对象的内存地址,以证明它们是不同的对象print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))if __name__ == '__main__':main()

更符合python方式实现,deepcopy

def pythonic_main():b1 = Book('The C Programming Language',('Brian W. Kernighan', 'Dennis M.Ritchie'),price=118,publisher='Prentice Hall',length=228,publication_date='1978-02-22',tags=('C', 'programming', 'algorithms', 'data structures'))# 这里我们彻底抛弃之前的原型设计模式的写法b2 = copy.deepcopy(b1)b2.name = 'The C Programming Language(ANSI)'b2.price = 48.99b2.length = 274b2.publication_date = '1988-04-01'b2.edition = 2for i in (b1, b2):print(i)print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))

总结

原型模式在处理复杂对象的复制时非常有用,它简化了对象的创建过程,并允许动态地改变对象的状态。不过,使用原型模式时,需要注意深复制和浅复制的区别,以及可能出现的循环引用问题。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 微软AD替代方案统一管理Windows和信创电脑的登录认证与网络准入认证
  • ARM体系与架构
  • C++AVL树
  • 后端输出二进制数据,前端fetch接受二进制数据,并转化为字符输出
  • 智能体进化发展了一年,现在的RPA Agent迭代到什么程度了?
  • 【初出江湖】SOA 与微服务:哪个最适合您的业务?
  • 计算机网络-BFD实验配置
  • 测试:TestGRPCDiscovery
  • docker实战基础二(Docker基础命令)
  • zset使用lua实现取最高分数中的随机成员
  • 干货含源码!如何用Java后端操作Docker(命令行篇)
  • Redis在服务器启动的日志问题
  • 选择排序的动画展示与实现
  • Ubuntu20上的Qt程序连接Windows上的mssql服务器
  • Oracle(ORA-00214)-undo表空间文件损坏
  • 【Leetcode】101. 对称二叉树
  • 【162天】黑马程序员27天视频学习笔记【Day02-上】
  • 08.Android之View事件问题
  • C++入门教程(10):for 语句
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • Gradle 5.0 正式版发布
  • Laravel5.4 Queues队列学习
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • SpringCloud(第 039 篇)链接Mysql数据库,通过JpaRepository编写数据库访问
  • Transformer-XL: Unleashing the Potential of Attention Models
  • use Google search engine
  • 不上全站https的网站你们就等着被恶心死吧
  • 分类模型——Logistics Regression
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 关于extract.autodesk.io的一些说明
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 推荐一个React的管理后台框架
  • 用Python写一份独特的元宵节祝福
  • ​​快速排序(四)——挖坑法,前后指针法与非递归
  • ​queue --- 一个同步的队列类​
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ​浅谈 Linux 中的 core dump 分析方法
  • ​软考-高级-系统架构设计师教程(清华第2版)【第9章 软件可靠性基础知识(P320~344)-思维导图】​
  • # C++之functional库用法整理
  • #java学习笔记(面向对象)----(未完结)
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2024.6.23)最新版MAVEN的安装和配置教程(超详细)
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (LeetCode 49)Anagrams
  • (第二周)效能测试
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (三)uboot源码分析
  • .CSS-hover 的解释
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET 8.0 发布到 IIS
  • .NET Core中如何集成RabbitMQ
  • .NET IoC 容器(三)Autofac