原型模式
以前聽過這樣一句話:“程式設計師的最高境界就是Ctrl+C、Ctrl+V”,我們先不論這句話的對錯,就論這個過程,這個過程我們都知道無非就是複製一個物件,然後將其不斷地貼上。這樣的過程我們可以將其稱之為“克隆”。再如我們應聘的時候列印了那麼多的簡歷。
克隆我們都清楚,就是用一個物體複製若干個一模一樣物體。同樣,在物件導向系統中,我們同樣可以利用克隆技術來克隆出若干個一模一樣的物件。在應用程式中,有些物件比較複雜,其建立過程過於複雜,而且我們又需要頻繁的利用該物件,如果這個時候我們按照常規思維new該物件,那麼務必會帶來非常多的麻煩,這個時候我們就希望可以利用一個已有的物件來不斷對他進行復制就好了,這就是程式設計中的“克隆”。這裡原型模式就可以滿足我們的“克隆”,在原型模式中我們可以利用過一個原型物件來指明我們所要建立物件的型別,然後通過複製這個物件的方法來獲得與該物件一模一樣的物件例項。這就是原型模式的設計目的。
模式定義
通過前面的簡單介紹我們就可以基本確定原型模式的定義了。所謂原型模式就是用原型例項指定建立物件的種類,並且通過複製這些原型建立新的物件。
在原型模式中,所發動建立的物件通過請求原型物件來拷貝原型物件自己來實現建立過程,當然所發動建立的物件需要知道原型物件的型別。這裡也就是說所發動建立的物件只需要知道原型物件的型別就可以獲得更多的原型例項物件,至於這些原型物件時如何建立的根本不需要關心。
講到原型模式了,我們就不得不區分兩個概念:深拷貝、淺拷貝。
淺拷貝:使用一個已知例項對新建立例項的成員變數逐個賦值,這個方式被稱為淺拷貝。
深拷貝:當一個類的拷貝構造方法,不僅要複製物件的所有非引用成員變數值,還要為引用型別的成員變數建立新的例項,並且初始化為形式引數例項值。
對於深淺拷貝以前的文章介紹過
複製程式碼
角色
原型模式主要包含如下三個角色:
Prototype:抽象原型類。宣告克隆自身的介面。
ConcretePrototype:具體原型類。實現克隆的具體操作。
Client:客戶類。讓一個原型克隆自身,從而獲得一個新的物件。
複製程式碼
優點 1、如果建立新的物件比較複雜時,可以利用原型模式簡化物件的建立過程,同時也能夠提高效率。
2、可以使用深克隆保持物件的狀態。
3、原型模式提供了簡化的建立結構。
缺點 1、在實現深克隆的時候可能需要比較複雜的程式碼。
2、需要為每一個類配備一個克隆方法,而且這個克隆方法需要對類的功能進行通盤考慮,這對全新的類來說不是很難,但對已有的類進行改造時,不一定是件容易的事,必須修改其原始碼,違背了“開閉原則”。
對於以上缺點python中有專門處理深克隆的方法deepcopy
模式使用場景 1、如果建立新物件成本較大,我們可以利用已有的物件進行復制來獲得。
2、如果系統要儲存物件的狀態,而物件的狀態變化很小,或者物件本身佔記憶體不大的時候,也可以使用原型模式配合備忘錄模式來應用。相反,如果物件的狀態變化很大,或者物件佔用的記憶體很大,那麼採用狀態模式會比原型模式更好。 3、需要避免使用分層次的工廠類來建立分層次的物件,並且類的例項物件只有一個或很少的幾個組合狀態,通過複製原型物件得到新例項可能比使用建構函式建立一個新例項更加方便。
程式碼實現
#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
大話設計模式
設計模式——原型模式
原型模式(Prototype Pattern):用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件
原型模式是用場景:需要大量的基於某個基礎原型進行微量修改而得到新原型時使用
"""
from copy import copy, deepcopy
# 原型抽象類
class Prototype(object):
def clone(self):
pass
def deep_clone(self):
pass
# 工作經歷類
class WorkExperience(object):
def __init__(self):
self.timearea = ''
self.company = ''
def set_workexperience(self,timearea, company):
self.timearea = timearea
self.company = company
# 簡歷類
class Resume(Prototype):
def __init__(self,name):
self.name = name
self.workexperience = WorkExperience()
def set_personinfo(self,sex,age):
self.sex = sex
self.age = age
pass
def set_workexperience(self,timearea, company):
self.workexperience.set_workexperience(timearea, company)
def display(self):
print self.name
print self.sex, self.age
print '工作經歷',self.workexperience.timearea, self.workexperience.company
def clone(self):
return copy(self)
def deep_clone(self):
return deepcopy(self)
if __name__ == '__main__':
obj1 = Resume('andy')
obj2 = obj1.clone() # 淺拷貝物件
obj3 = obj1.deep_clone() # 深拷貝物件
obj1.set_personinfo('男',28)
obj1.set_workexperience('2010-2015','AA')
obj2.set_personinfo('男',27)
obj2.set_workexperience('2011-2017','AA') # 修改淺拷貝的物件工作經歷
obj3.set_personinfo('男',29)
obj3.set_workexperience('2016-2017','AA') # 修改深拷貝的物件的工作經歷
obj1.display()
obj2.display()
obj3.display()
複製程式碼