Prototype
動機(motivation)
- 在軟件系統(tǒng)中,經(jīng)常面臨這“某些結(jié)構(gòu)復(fù)雜的對象”的創(chuàng)建工作仙蛉;由于需求的變化荐健,這些對象經(jīng)常面臨著劇烈的變化,但是它們卻擁有比較穩(wěn)定一致的接口弄喘。
- 如何應(yīng)對這種變化?如何向“客戶程序(使用這些對象的程序)”隔離出“這些易變對象”甩牺,從而使得依賴這些”易變對象“的客戶程序不隨著需求改變而改變蘑志。
模式定義
使用原型實例指定創(chuàng)建對象的種類,然后通過拷貝這些原型來創(chuàng)建新的對象贬派。
——《設(shè)計模式》GoF
要點總結(jié)
- Prototype模式同樣用于隔離對象的使用者和具體類型(易變類)之間的耦合關(guān)系急但,它同樣要求這些“易變類”擁有穩(wěn)定的接口。
- Prototype模式對于“如何創(chuàng)建易變類的實體對象“采用”原型克隆“的方法來做搞乏,
它使得我們可以非常靈活地動態(tài)創(chuàng)建”擁有某些穩(wěn)定接口“的新對象——所需工作僅僅是注冊一個新類的對象(即原型)波桩,
然后在任何需要的地方Clone。 - Prototype模式中的Clone方法可以利用某些框架中的序列化來實現(xiàn)深拷貝请敦。
例子
# -*- coding: utf-8 -*-
import copy
from collections import OrderedDict
class Book(object):
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(object):
def __init__(self):
self.objects = dict()
def register(self, identifier, obj):
self.objects[identifier] = obj
def unregister(self, identifier):
if identifier in self.objects:
del self.objects[identifier]
def clone(self, identifier, **kwargs):
prototype_obj = self.objects.get(identifier)
if not prototype_obj:
raise ValueError('Incorrect object identifier: {}'.format(identifier))
obj = copy.deepcopy(prototype_obj)
obj.__dict__.update(kwargs)
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()
- 例子中以之前創(chuàng)建的
Book類
對象b1
為原型萤皂,創(chuàng)建了對象b2