源碼地址:https://github.com/weilanhanf/PythonDesignPatterns
說明:
有時為了給某個對象而不是給整個類添加一個功能,使用繼承機制是添加功能的一個有效途徑,但是不夠靈活,用戶不能控制對組件加邊框的方式和時機,並且會導致子類膨脹。一種較為靈活的方式就是將組件嵌入另一個對象中,這個嵌入的對象叫做裝飾。
裝飾模式:動態地給一個對象增加一些額外的職責。就擴展功能而言,裝飾模式提供了一種比使用子類更加靈活的替代方案。以對客戶透明的方式動態地給一個對象附加上更多的責任 可以在不需要創建更多子類的情況下,讓對象的功能得以擴展
裝飾模式分析
可以在不改變一個對象本身功能的基礎上給對象增加額外的新行為 是一種用於替代繼承的技術,它通過一種無須定義子類的方式給對象動態增加職責,使用對象之間的關聯關系取代類之間的繼承關系 引入了裝飾類,在裝飾類中既可以調用待裝飾的原有類的方法,還可以增加新的方法,以擴展原有類的功能
裝飾模式的結構
裝飾模式包含以下4個角色: Component(抽象構件) ConcreteComponent(具體構件) Decorator(抽象裝飾類) ConcreteDecorator(具體裝飾類)
實例:
#又提到了那個快餐點餐系統,不過今天我們只以其中的一個類作為主角:飲料類。首先,回憶下飲料類: class Beverage(): name = "" price = 0.0 type = "BEVERAGE" def getPrice(self): return self.price def setPrice(self, price): self.price = price def getName(self): return self.name class coke(Beverage): def __init__(self): self.name = "coke" self.price = 4.0 class milk(Beverage): def __init__(self): self.name = "milk" self.price = 5.0 #除了基本配置,快餐店賣可樂時,可以選擇加冰,如果加冰的話,要在原價上加0.3元; # 賣牛奶時,可以選擇加糖,如果加糖的話,要原價上加0.5元。怎么解決這樣的問題? # 可以選擇裝飾器模式來解決這一類的問題。首先,定義裝飾器類: class drinkDecorator(): def getName(self): pass def getPrice(self): pass class iceDecorator(drinkDecorator): def __init__(self, beverage): self.beverage = beverage def getName(self): return self.beverage.getName() + " +ice" def getPrice(self): return self.beverage.getPrice() + 0.3 class sugarDecorator(drinkDecorator): def __init__(self, beverage): self.beverage = beverage def getName(self): return self.beverage.getName() + " +sugar" def getPrice(self): return self.beverage.getPrice() + 0.5 #構建好裝飾器后,在具體的業務場景中,就可以與飲料類進行關聯。以可樂+冰為例,示例業務場景如下: if __name__=="__main__": coke_cola=coke() print("Name:%s"%coke_cola.getName()) print("Price:%s"%coke_cola.getPrice()) ice_coke=iceDecorator(coke_cola) print("Name:%s" % ice_coke.getName()) print("Price:%s" % ice_coke.getPrice())
打印結果:
Name:coke
Price:4.0
Name:coke +ice
Price:4.3
模式優點
對於擴展一個對象的功能,裝飾模式比繼承更加靈活,不會導致類的個數急劇增加 可以通過一種動態的方式來擴展一個對象的功能,通過配置文件可以在運行時選擇不同的具體裝飾類,從而實現不同的行為 可以對一個對象進行多次裝飾 具體構件類與具體裝飾類可以獨立變化,用戶可以根據需要增加新的具體構件類和具體裝飾類,且原有類庫代碼無須改變,符合開閉原則
模式缺點
使用裝飾模式進行系統設計時將產生很多小對象,大量小對象的產生勢必會占用更多的系統資源,在一定程度上影響程序的性能 比繼承更加易於出錯,排錯也更困難,對於多次裝飾的對象,調試時尋找錯誤可能需要逐級排查,較為煩瑣
模式適用環境
在不影響其他對象的情況下,以動態、透明的方式給單個對象添加職責 當不能采用繼承的方式對系統進行擴展或者采用繼承不利於系統擴展和維護時可以使用裝飾模式