一、理解原型模式
原型模式就是帮助创建对象的克隆,有时候需要在对象的副本上进行操作,这样不会改变原对象的变量。假如figt和lice是两位厨师,现在figt有一份关于红烧肉的配料,他想分享给lice,那么如果lice想在配料谱上做修改,是否figt拿到的也会跟着变呢?
如果是上图这样的表示figt与lice对同一个配料谱的引用,如果lice做了修改,figt看到的就是修改过后的内容,而且修改的时间不同,内容可能也会不同。但是这是不希望看到的,lice应该拥有figt的副本,这样修改自己的对figt没有影响。
如上所示,这样lice就拥有自己的副本了,随意修改,不影响figt。在python中可以通过copy.deepcopy来完成。
二、原型模式的实现
import copy class A: def __init__(self): self.x=3 if __name__=="__main__": a=A() b=copy.deepcopy(a) print(a) print(b) ##################输出########### #<__main__.A object at 0x00000000004F6828> #<__main__.A object at 0x00000000004F68D0>
使用deepcopy函数算是比较简单的完成原型模式,可以看到两个对象的地址不同,说明已经完成了a对象的副本了。
三、应用案例
现在新建一个书籍相关的类,并且创建对象,然后利用这个对象再创建一个副本,并且可以在副本上进行修改。
from collections import OrderedDict import time, hashlib class Book: def __init__(self,name,authors,price,**kwargs): """ :param name: :param authors: :param price: :param kwargs: 出版商、出版日期等,关键词的形式(名称=值)传入更多的参数 """ self.name=name self.authors=authors self.price=price self.__dict__.update(kwargs) def create(self): """ 给自己对象创建一个唯一id :return: """ m = hashlib.md5() m.update(bytes(str(time.time()), encoding="utf-8")) return m.hexdigest() def __str__(self): list=[] ordered = OrderedDict(sorted(self.__dict__.items())) #每次打印出对象的内容不会改变顺序 for i in ordered.keys(): list.append("%s:%s"%(i,ordered[i])) if i=="price": list.append("$") list.append(" ") return "".join(list)
然后再创建一个专门用于clone的类Prototype
import copy 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] #删除对象的引用,触发析构方法__del__ def clone(self,identifier,**attr): #attr用于在副本上进行修改,添加其它参数 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
然后可以进行实例以及调用方法
b1=Book("Python设计","Bjg",20,pub_date="2018-03-01") #实例化Book类 b1_id=b1.create()#生成b1对象id prototype=Prototype() prototype.register(b1_id,b1) #将对象与id进行绑定 b2=prototype.clone(b1_id,edition=3) #获取b1的副本,并且对副本进行了修改,添加edition=3 print(b1) print(b1.__dict__) print(b2) print(b2.__dict__) ######################输出############### # authors:Bjg # name:Python设计 # price:20$ # pub_date:2018-03-01 # # {'price': 20, 'name': 'Python设计', 'pub_date': '2018-03-01', 'authors': 'Bjg'} # authors:Bjg # edition:3 # name:Python设计 # price:20$ # pub_date:2018-03-01 # # {'edition': 3, 'name': 'Python设计', 'authors': 'Bjg', 'pub_date': '2018-03-01', 'price': 20}
参考:精通Python设计模式一书