本篇的裝飾器模式不是講解的python中的語法糖 @ 這個裝飾器。而是講解設計模式中的裝飾器模式。網上不少的實現都是基於java和c++的。本文則使用python來實現,其中有些實現可能在python並不須要那樣來寫的,可是思路都是同樣的。關於python @ 裝飾器的使用我以後會再寫一篇文章來介紹。html
你們知道咱們有的時候老是須要給給一個類或者一個對象增長一些行爲。通常狀況下使用繼承和關聯兩種方式來實現。其中使用關聯這種方式來實現並符合必定的設計規範的咱們稱之爲裝飾器模式。接下來咱們首先會先介紹一下這兩種方法,而後用python代碼來分別實現這兩種方法並比較他們之間的差別。java
通常狀況下咱們都是經過繼承來給一個或一羣類來添加方法,經過繼承使子類得到了父類的行爲。雖然繼承是一種適用普遍的方法,可是繼承是一種靜態行爲,在代碼編寫階段就已經固定,沒法動態的控制一個類增長行爲的種類和時間。python
咱們經過將一個A對象嵌入另外一個B對象裏面,及將一個B對象裏面的屬性的值設置爲A對象。經過在調用A對象的動做先後添加行爲來給A對象增長功能。這種模式咱們稱之爲裝飾器模式。 c++
「裝飾模式以對客戶透明的方式動態地給一個對象附加上更多的責任,換言之,客戶端並不會以爲對象在裝飾前和裝飾後有什麼不一樣。裝飾模式能夠在不須要創造更多子類的狀況下,將對象的功能加以擴展。這就是裝飾模式的模式動機。」[1] 設計模式
由於裝飾器模式是在給對象增長責任。因此裝飾器模式爲對象結構型設計模式(對象是由於其是給對象而不是類增長責任,結構型模式就是描述如何將類或者對象結合在一塊兒造成更大的結構,就像搭積木,能夠經過簡單積木的組合造成複雜的、功能更爲強大的結構)。架構
一個飲料店裏面賣茶和咖啡。 而且有冰塊,糖和牛奶三種輔料能夠添加。 咱們能夠計算出一共有14中組合產品。而且每增長一種飲料就要增長7種組合產品。spa
class DrinkComponent(object): def get_price(self): pass def get_name(self): pass class TeaConcreteComponent(DrinkComponent): def __init__(self): self.__name = 'Tea' self.__price = 2 def get_price(self): return self.__price def get_name(self): return self.__name class CoffeeConcreteComponent(DrinkComponent): def __init__(self): self.__name = 'coffee' self.__price = 3 def get_price(self): return self.__price def get_name(self): return self.__name class IngredientsComponent(object): pass class IceConcreteComponent(IngredientsComponent): def add_ice_price(self): return 0.3 def add_ice_name(self): return '+Ice' class SugerConcreteComponent(IngredientsComponent): def add_suger_price(self): return 0.5 def add_suger_name(self): return '+Suger' class MilkConcreteComponent(IngredientsComponent): def add_milk_price(self): return 1 def add_milk_name(self): return '+Milk' class Tea_Milk(TeaConcreteComponent, MilkConcreteComponent): def get_price(self): return TeaConcreteComponent.get_price(self) + MilkConcreteComponent.add_milk_price(self) def get_name(self): return TeaConcreteComponent.get_name(self) + MilkConcreteComponent.add_milk_name(self) class Tea_Milk_Ice(TeaConcreteComponent, MilkConcreteComponent, IceConcreteComponent): def get_price(self): return TeaConcreteComponent.get_price(self) + MilkConcreteComponent.add_milk_price(self) \ + IceConcreteComponent.add_ice_price(self) def get_name(self): return TeaConcreteComponent.get_name(self) + MilkConcreteComponent.add_milk_name(self)\ + IceConcreteComponent.add_ice_name(self) if __name__ == '__main__': tea_milk = Tea_Milk() print tea_milk.get_name() print tea_milk.get_price() tea_milk_ice = Tea_Milk_Ice() print tea_milk_ice.get_name() print tea_milk_ice.get_price()
從圖和代碼中看首先咱們定義了DrinkComponent和IngredientsComponent即飲料和配料兩個抽象類,並分別實現了具體的構建類。當咱們要產生一個產品的時候。經過繼承不一樣的具體構建類來實現。好比加冰加牛奶的茶。咱們經過繼承茶、牛奶和冰塊三個類來實現。能夠看出若是要實現全部的類那麼咱們須要14個子類來完成。支持多繼承的語言才能這樣實現若是是單繼承的語言則須要經過多級繼承來完成。不只冗餘度增長並且複雜的多級繼承關係是後期維護的淚。設計
class DrinkComponent(object): def get_price(self): pass def get_name(self): pass class TeaConcreteComponent(DrinkComponent): def __init__(self): self.__name = 'Tea' self.__price = 2 def get_price(self): return self.__price def get_name(self): return self.__name class CoffeeConcreteComponent(DrinkComponent): def __init__(self): self.__name = 'coffee' self.__price = 3 def get_price(self): return self.__price def get_name(self): return self.__name class IngredientsDecorator(DrinkComponent): def __init__(self, drink_component): self.drink_component = drink_component def get_price(self): pass def get_name(self): pass class IceConcreteDecorator(IngredientsDecorator): def get_price(self): return self.drink_component.get_price() + self.add_ice_price() def add_ice_price(self): return 0.3 def get_name(self): return self.drink_component.get_name() + self.add_ice_name() def add_ice_name(self): return '+Ice' class SugerConcreteDecorator(IngredientsDecorator): def get_price(self): return self.drink_component.get_price() + self.add_suger_price() def add_suger_price(self): return 0.5 def get_name(self): return self.drink_component.get_name() + self.add_suger_name() def add_suger_name(self): return '+Suger' class MilkConcreteDecorator(IngredientsDecorator): def get_price(self): return self.drink_component.get_price() + self.add_milk_price() def add_milk_price(self): return 1 def get_name(self): return self.drink_component.get_name() + self.add_milk_name() def add_milk_name(self): return '+Milk' if __name__ == '__main__': tea_milk = MilkConcreteDecorator(TeaConcreteComponent()) print tea_milk.get_name() print tea_milk.get_price() tea_milk_ice = IceConcreteDecorator(MilkConcreteDecorator(TeaConcreteComponent())) print tea_milk_ice.get_name() print tea_milk_ice.get_price()
DrinkComponent 是抽象構件類,它是具體構建類(*ConcreteComponent)和抽象裝飾器類(IngredientsDecorator)的父類,主要定義了具體構建類的業務方法。以及讓咱們在調用的時候能夠統一的處理裝飾前和裝飾後的對象。方便咱們使用裝飾器類裝飾一個已經被裝飾的具體構建如加糖(加冰(咖啡))。在關聯關係中咱們主要說一下這個部分。 code
這是一個關聯聚合關係。表示IngredientsDecorator是知道DrinkComponent類的存在的呢。這個你們能夠這樣理解。你在實現Concretecomponet的時候是不須要考慮IngredinetsDecorator的存在,由於你不會調用它的,也不繼承它,也不知道你會被它調用。可是在設計實現ConcreteDecorator的時候你會在其屬性中保持一個對DrinkComponet類型的類的引用。而且你會調用她的方法。這樣你就要知道DrinkCompoent這個類裏面都有什麼方法及要知道DrinkComponent類的存在。在另外一種設計模式橋接模式這種關係正好是相反的。我以後再來寫一篇關於橋接模式的介紹。component
咱們在代碼中能夠看到在IngredientsDecorator中也有get_price 和 get_name兩種方法。這是爲了保證在ConcreteComponent在被裝飾器後仍是能夠像沒有被裝飾那樣被調喲個。而且咱們能夠在調用的上面和下面添加功能以實現功能的加強。好比咱們在代碼中是這樣寫的
def get_price(self): return self.drink_component.get_price() + self.add_milk_price()
咱們也能夠將其改寫爲這樣
def get_price(self): print 'add Milk' price = self.drink_component.get_price() new_price = price + self.add_milk_price() return new_price
咱們在調用被修飾的類的前面增長了一個功能打印 'add milk'這件事,並在獲取了裝飾的產品價格後給架構增長了一個牛奶的價格並將其返回。
經過裝飾模式來擴展對象的功能比繼承模式更靈活。構建和裝飾器能夠獨立擴展,新增功能不須要添加大量的子類。可是裝飾模式也產生了許多小對象,增長了排錯的難度。
如下狀況適合使用裝飾器模式:
在不影響其餘對象的狀況下,以動態、透明的方式給單個對象添加職責。
須要動態地給一個對象增長功能,這些功能也能夠動態地被撤銷。
當不能採用繼承的方式對系統進行擴充或者採用繼承不利於系統擴展和維護時。不能採用繼承的狀況主要有兩類:第一類是系統中存在大量獨立的擴展,爲支持每一種組合將產生大量的子類,使得子類數目呈爆炸性增加;第二類是由於類定義不能繼承(如final類).[1]