原型模式
1.定义
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
2.类图
3.副本与引用的区别
下图展示了副本与引用的区别:
对引用的操作,也就是对原来真正的数据进行操作。
而对副本的操作,对原来真正的数据并不影响。
4.代码示例:
原型设计模式帮助我们创建一个对象的的克隆,其最简单的形式就是一个clone() 函数,接受一个对象作为输入参数,返回输入对象的一个副本。
实例:
from collections import OrderedDict import copy class Book: def __init__(self,name,authors,price,**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): found = self.objects.get(identifier) if not found: raise ValueError('Incorrect object') obj = copy.deepcopy(found) obj.__dict__.update(attr) return obj def main(): b1 = Book('the c programmng 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()
5.优点
使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单
6.注意事项
- 使用原型模式复制对象不会调用类的构造方法。因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。
- 深拷贝与浅拷贝。Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。
7.总结
原型模式用于创建对象的完全副本。创建一个对象的副本可以指代以下两件事情:
当创建一个浅副本时,副本依赖引用
当创建一个深副本时,副本复制所有东西
第一种情况中,我们关注提升应用性能和优化内存使用,在对象之间引入数据共享,但需要
小心地修改数据,因为所有变更对所有副本都是可见的。
第二种情况中,我们希望能够对一个副本进行更改而不会影响其他对象。