又提到了那個快餐點餐系統,不過今天我們隻以其中的一個類作為主角:飲料類。首先,回憶下飲料類:
除了基本配置,快餐店賣可樂時,可以選擇加冰,如果加冰的話,要在原價上加0.3元;賣牛奶時,可以選擇加糖,如果加糖的話,要原價上加0.5元。怎麼解決這樣的問題?可以選擇裝飾器模式來解決這一類的問題。首先,定義裝飾器類:
建構好裝飾器後,在具體的業務場景中,就可以與飲料類進行關聯。以可樂+冰為例,示例業務場景如下:
列印結果如下:
name:coke
price:4.0
name:coke +ice
price:4.3
裝飾器模式定義如下:動态地給一個對象添加一些額外的職責。在增加功能方面,裝飾器模式比生成子類更為靈活。
裝飾器模式和上一節說到的代理模式非常相似,可以認為,裝飾器模式就是代理模式的一個特殊應用,兩者的共同點是都具有相同的接口,不同點是側重對主題類的過程的控制,而裝飾模式則側重對類功能的加強或減弱。
上一次說到,java中的動态代理模式,是實作aop的重要手段。而在python中,aop通過裝飾器模式實作更為簡潔和友善。
先來解釋一下什麼是aop。aop即aspect oriented programming,中文翻譯為面向切面的程式設計,它的含義可以解釋為:如果幾個或更多個邏輯過程中(這類邏輯過程可能位于不同的對象,不同的接口當中),有重複的操作行為,就可以将這些行為提取出來(即形成切面),進行統一管理和維護。舉例子說,系統中需要在各個地方列印日志,就可以将列印日志這一操作提取出來,作為切面進行統一維護。
從程式設計思想的關系來看,可以認為aop和oop(面向對象的程式設計)是并列關系,二者是可以替換的,也可以結合起來用。實際上,在python語言中,是天然支援裝飾器的,如下例:
列印如下:
call now():
2016-12-04
log接口就是裝飾器的定義,而python的@文法部分則直接支援裝飾器的使用。
如果要在快餐點餐系統中列印日志,該如何進行aop改造呢?可以借助類的靜态方法或者類方法來實作:
在需要列印日志的地方直接@logmanager.log,即可列印出通路的日志資訊。如,在beverage類的函數前加上@logmanager.log,場景類保持不變,則列印結果如下:
visit func getname
visit func getprice
優點:
1、裝飾器模式是繼承方式的一個替代方案,可以輕量級的擴充被裝飾對象的功能;
2、python的裝飾器模式是實作aop的一種方式,便于相同操作位于不同調用位置的統一管理。
應用場景:
1、需要擴充、增強或者減弱一個類的功能,如本例。
1、多層裝飾器的調試和維護有比較大的困難。