4-Python與設計模式–原型模式
一、圖層
大家如果用過類似于Photoshop的平面設計軟件,一定都知道圖層的概念。圖層概念的提出,
使得設計、圖形修改等操作更加便利。設計師既可以修改和繪制當前圖像對象,又可以保留其它
圖像對象,邏輯清晰,且可以及時得到反饋。本節內容,將以圖層為主角,介紹原型模式。
首先,設計一個圖層對象。
class simpleLayer:background=[0,0,0,0]content="blank"def getContent(self):return self.contentdef getBackgroud(self):return self.backgrounddef paint(self,painting):self.content=paintingdef setParent(self,p):self.background[3]=pdef fillBackground(self,back):self.background=back
在實際的實現中,圖層實現會很復雜,這里僅介紹相關的設計模式,做了比較大的抽象,用
background表示背景的RGBA,簡單用content表示內容,除了直接繪畫,還可以設置透明度。
新建圖層,填充藍底并畫一只狗,可以簡單表示如下:
if __name__=="__main__":dog_layer=simpleLayer()dog_layer.paint("Dog")dog_layer.fillBackground([0,0,255,0])print "Background:",dog_layer.getBackgroud()print "Painting:",dog_layer.getContent()
打印如下: Background: [0, 0, 255, 0] Painting: Dog
接下來,如果需要再生成一個同樣的圖層,再填充同樣的顏色,再畫一只同樣狗,該如何做呢?
還是按照新建圖層、填充背景、畫的順序么?或許你已經發現了,這里可以用復制的方法來實現,
而復制(clone)這個動作,就是原型模式的精髓了。
按照此思路,在圖層類中新加入兩個方法:clone和deep_clone
from copy import copy, deepcopy
class simpleLayer:background=[0,0,0,0]content="blank"def getContent(self):return self.contentdef getBackgroud(self):return self.backgrounddef paint(self,painting):self.content=paintingdef setParent(self,p):self.background[3]=pdef fillBackground(self,back):self.background=backdef clone(self):return copy(self)def deep_clone(self):return deepcopy(self)
if __name__=="__main__":dog_layer=simpleLayer()dog_layer.paint("Dog")dog_layer.fillBackground([0,0,255,0])print "Background:",dog_layer.getBackgroud()print "Painting:",dog_layer.getContent()another_dog_layer=dog_layer.clone()print "Background:", another_dog_layer.getBackgroud()print "Painting:", another_dog_layer.getContent()
打印結果如下: Background: [0, 0, 255, 0] Painting: Dog Background: [0, 0,
255, 0] Painting: Dog
clone和deep_clone有什么區別呢?
大多數編程語言中,都會涉及到深拷貝和淺拷貝的問題,一般來說,淺拷貝會拷貝對象內容及其內容的引用或者
子對象的引用,但不會拷貝引用的內容和子對象本身;而深拷貝不僅拷貝了對象和內容的引用,也會拷貝引用的
內容。所以,一般深拷貝比淺拷貝復制得更加完全,但也更占資源(包括時間和空間資源)。舉個例子,
下面的場景,可以說明深拷貝和淺拷貝的區別。
if __name__=="__main__":dog_layer=simpleLayer()dog_layer.paint("Dog")dog_layer.fillBackground([0,0,255,0])print "Original Background:",dog_layer.getBackgroud()print "Original Painting:",dog_layer.getContent()another_dog_layer=dog_layer.clone()another_dog_layer.setParent(128)another_dog_layer.paint("Puppy")print "Original Background:", dog_layer.getBackgroud()print "Original Painting:", dog_layer.getContent()print "Copy Background:", another_dog_layer.getBackgroud()print "Copy Painting:", another_dog_layer.getContent()
打印如下:
Original Background: [0, 0, 255, 0] Original Painting: Dog Original
Background: [0, 0, 255, 128] Original Painting: Dog Copy Background:
[0, 0, 255, 128] Copy Painting: Puppy淺拷貝后,直接對拷貝后引用(這里的數組)進行操作,原始對象中該引用的內容也會變動。如果將another_dog_layer=dog_layer.clone()換成another_dog_layer=dog_layer.deep_clone(),即把淺拷貝換成深拷貝,其如果如下:
Original Background: [0, 0, 255, 0] Original Painting: Dog Original
Background: [0, 0, 255, 0] Original Painting: Dog Copy Background: [0,
0, 255, 128] Copy Painting: Puppy
深拷貝后,其對象內的引用內容也被進行了復制。
二、原型模式
原型模式定義如下:用原型實例指定創建對象的種類,并且通過復制這些原型創建新的對象。
需要注意一點的是,進行clone操作后,新對象的構造函數沒有被二次執行,
新對象的內容是從內存里直接拷貝的。
三、原型模式的優點和使用場景
3.1 優點:
1、性能極佳,直接拷貝比在內存里直接新建實例節省不少的資源;
2、簡化對象創建,同時避免了構造函數的約束,不受構造函數的限制直接復制對象,
是優點,也有隱患,這一點還是需要多留意一些。
3.2 使用場景:
1、對象在修改過后,需要復制多份的場景。如本例和其它一些涉及到復制、粘貼的場景;
2、需要優化資源的情況。如,需要在內存中創建非常多的實例,可以通過原型模式來減少資源
消耗。此時,原型模式與工廠模式配合起來,不管在邏輯上還是結構上,都會達到不錯的效果;
3、某些重復性的復雜工作不需要多次進行。如對于一個設備的訪問權限,多個對象不用各申請一遍
權限,由一個設備申請后,通過原型模式將權限交給可信賴的對象,既可以提升效率,
又可以節約資源。
四、原型模式的缺點
1、深拷貝和淺拷貝的使用需要事先考慮周到;
2、某些編程語言中,拷貝會影響到靜態變量和靜態函數的使用。