浅谈Python设计模式 - 原型模式
声明,本系列文章主要参考《精通Python设计模式》一书,并且参考一些资料,结合自己的一些看法来总结而来。
在《精通Python设计模式》中把设计模式分为三种类型:
- 创建型模式
- 结构型模式
- 行为型模式
本篇主要介绍关于 创建型模式的一种,书上的说法为:
当我们已有一个对象,并希望创建该对象的一个完整副本时,原型模式就派上用场了。在我们知道对象的某些部分会被变更但又希望保持原有对象不变之时,通常需要对象的一个副本。在这样的案例中,重新创建原有对象是没有意义的(请参考网页[ Mitotic division ])。
另一个案例是,当我们想复制一个复杂对象时,使用原型模式会很方便。对于复制复杂对象,我们可以将对象当作是从数据库中获取的,并引用其他一些也是从数据库中获取的对象。若通过多次重复查询数据来创建一个对象,则要做很多工作。在这种场景下使用原型模式要方便得多。
个人理解:
当我们已经存在一个对象,这个对象有其属性和方法,若我们还想去获得另外一个同类型对象,此时有两种选择:重新去创建一个新的对象,或者 根据已有的对象复制一个副本,而在很多时候我们不需要完全去重新构建一个对象,只需要在原有对象存在的基础上(保留原对象),去修改其属性和方法得到一个新的对象。
其实通俗解释来说:
比如:当我们出版了一本书《Python 设计模式 1.0版》,若10 年后我们觉得这本书跟不上时代了,这时候需要去重写一本《Python 设计模式 2.0版》,那么我们是完全重写一本书呢?还是在原有《Python 设计模式 1.0版》的基础上进行修改呢?当然是后者,这样会省去很多排版、添加原有知识等已经做过的工作。
接下来看一下书中的示例源码:
import copy
from collections import OrderedDict class Book:
def __init__(self, name, authors, price, **rest):
'''rest的例子有:出版商、长度、标签、出版日期'''
self.name = name
self.authors = authors
self.price = price
self.__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] = obj def 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 obj def 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()
cid = 'k&r-first'
prototype.register(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()
其输出结果为:
authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')
authors: ('Brian W. Kernighan', 'Dennis M.Ritchie')
edition: 2
length: 274
name: The C Programming Language(ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')
ID b1 : 2378797084512 != ID b2 : 2378796684008
其实这段代码在 Python 中,我们要实现一样的效果,并没有这么复杂,完全可以不使用这样的方法,我们更熟悉的方法是这样的,这里只修改 main 函数:
def 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.99
b2.length = 274
b2.publication_date = '1988-04-01'
b2.edition = 2 for i in (b1, b2):
print(i)
print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))
所以说:同样的内容,经过不同的方式,可以得到同样的效果。
《Python设计模式》中也提及到,大概意思如下:
设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。
这里不是说书中实例的原型模式没有用,而是说 有些时候可以用简单粗暴的方式实现,何必整的那么弯弯绕绕呢?当然,视情况而定吧。
over~~~~~~~~
浅谈Python设计模式 - 原型模式的更多相关文章
- 浅谈Python设计模式 - 外观模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 外观模式 外观模式的核心在于将复杂的内部实现包装起来,只向外界提供简单的调用接口 ...
- 浅谈Python设计模式 - 代理模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...
- 浅谈Python设计模式 - 建造者模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 建造者模式 当我们想要创建一个由多个部分构成的对象,而且他们的构建需要一步接一步 ...
- 浅谈Python设计模式 - 工厂模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 工厂模式: 顾名思义,工厂则是根据提供的不同的材料,生产出不同的产品.那么在编程 ...
- 浅谈Python设计模式 -- 责任链模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 之前在最开始就聊了Python设计模式有三种,其中关于创建型和结构型设计模式基本 ...
- 浅谈Python设计模式 - 享元模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 享元模式: 享元模式是一种用于解决资源和性能压力时会使用到的设计模式,它的核心思 ...
- 浅谈Python设计模式 - 抽象工厂模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在上一篇我们对工厂模式中的普通工厂模式有了一定的了解,其实抽象工作就是 表示针对 ...
- 浅谈Python设计模式 - 适配器模式
声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 从本篇便开始介绍结构型设计模式,而适配器设计模式便是该类设计模式的一种,那么什么 ...
- 浅谈js设计模式 — 命令模式
命令模式最常见的应用场景是:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么.此时希望用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦 ...
随机推荐
- C语言实现linux之who功能
/* who_test.c */ #include<stdio.h> #include<string.h> #include<getopt.h> #include& ...
- TensorFlow实现文本情感分析详解
http://c.biancheng.net/view/1938.html 前面我们介绍了如何将卷积网络应用于图像.本节将把相似的想法应用于文本. 文本和图像有什么共同之处?乍一看很少.但是,如果将句 ...
- 抓住九月的尾巴分享一个插件XLSX
git官网 安装: cnpm install --save xlsx file-saver .vue文件中:1. 引用table插件/自己写table布局 <el-table id=" ...
- Linux搭建简单的http文件服务器
为了让自动化脚本可以通过wget来下载安装包,需要在集群中的某个节点部署一个http文件服务器 在Ubuntu中通过apt-get install apache2 安装apache2CentOS7中通 ...
- shell脚本监控httpd服务80端口状态
监控httpd服务端口状态,根据端口判断服务器是否启动,如果没有启动则脚本自动拉起服务,如果服务正在运行则退出脚本程序:如果换成别的服务端口也可以,但是脚本程序需要做调整. #!/bin/bash # ...
- Sitecore 9 为什么数据驱动的组织选择它
Sitecore 9使用个性化和机器学习来帮助客户提高数字营销对数字投资的回报 Sitecore 9比以往任何时候都更加智能.主要功能包括: 数据集中化 向后兼容性 简单的迁移 该平台简化了营销人员和 ...
- golang 学习笔记 --基本类型
字符串值表示了一个一个字符值的集合,在底层,一个字符串值即一个包含了若干字节的序列,长度为0的序列与一个空字符串对应.字符串的长度即底层字节列中字节的个数. 字符串值是不可变的,对字符串的操作只会返回 ...
- golang学习笔记--函数和方法
在go中,函数类型是一等类型,这意味着可以吧函数当做一个值来传递和使用. func divide(dividend int,divisor int)(int,error){ //省略部分代码 } 参数 ...
- Github 上优秀的 Java 项目推荐
1.JavaGuide 地址:Snailclimb/JavaGuide [Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识. 2.DoraemonKit 地址:didi/Do ...
- Jquery源码解析及案例分析
本人刚学先上链接(别人写的挺好的)后期同步补上