一、快餐點餐系統
又提到了那個快餐點餐系統,不過今天我們只以其中的一個類作爲主角:飲料類。首先,回憶下飲料類:
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
'''
二、裝飾器模式
裝飾器模式定義如下:動態地給一個對象添加一些額外的職責。在增加功能方面,裝飾器模式比生成子類更爲靈活。
裝飾器模式和上一節說到的代理模式非常相似,可以認爲,裝飾器模式就是代理模式的一個特殊應用,兩者的共同點是都具有相同的接口,不同點是側重對主題類的過程的控制,而裝飾模式則側重對類功能的加強或減弱。
上一次說到,JAVA中的動態代理模式,是實現AOP的重要手段。而在Python中,AOP通過裝飾器模式實現更爲簡潔和方便。
先來解釋一下什麼是AOP。AOP即Aspect Oriented Programming,中文翻譯爲面向切面的編程,它的含義可以解釋爲:如果幾個或更多個邏輯過程中(這類邏輯過程可能位於不同的對象,不同的接口當中),有重複的操作行爲,就可以將這些行爲提取出來(即形成切面),進行統一管理和維護。舉例子說,系統中需要在各個地方打印日誌,就可以將打印日誌這一操作提取出來,作爲切面進行統一維護。
從編程思想的關係來看,可以認爲AOP和OOP(面向對象的編程)是並列關係,二者是可以替換的,也可以結合起來用。實際上,在Python語言中,是天然支持裝飾器的,如下例:
def log(func):
def wrapper(*args, **kw):
print 'call %s():' % func.__name__
return func(*args, **kw)
return wrapper
@log
def now():
print '2016-12-04'
if __name__=="__main__":
now()
'''
打印如下:
call now():
2016-12-04
'''
log接口就是裝飾器的定義,而Python的@語法部分則直接支持裝飾器的使用。
如果要在快餐點餐系統中打印日誌,該如何進行AOP改造呢?可以藉助類的靜態方法或者類方法來實現:
class LogManager:
@staticmethod
def log(func):
def wrapper(*args):
print "Visit Func %s"%func.__name__
return func(*args)
return wrapper
在需要打印日誌的地方直接@LogManager.log,即可打印出訪問的日誌信息。如,在beverage類的函數前加上@LogManager.log,場景類保持不變,則打印結果如下:
Visit Func getName
Name:coke
Visit Func getPrice
Price:4.0
Visit Func getName
Name:coke +ice
Visit Func getPrice
Price:4.3
三、裝飾器模式的優點和應用場景
優點:
1、裝飾器模式是繼承方式的一個替代方案,可以輕量級的擴展被裝飾對象的功能;
2、Python的裝飾器模式是實現AOP的一種方式,便於相同操作位於不同調用位置的統一管理。
應用場景:
1、需要擴展、增強或者減弱一個類的功能,如本例。
四、裝飾器模式的缺點
1、多層裝飾器的調試和維護有比較大的困難。