什么是 開放-封閉原則
開放是對(duì)擴(kuò)展開放,也就是能支持功能的擴(kuò)展
封閉是對(duì)原功能封閉,這意思是當(dāng)功能擴(kuò)展的時(shí)候并不用更改原來(lái)的代碼
什么是裝飾器模式
裝飾器模式就是在不改變?cè)瓉?lái)代碼的基礎(chǔ)上增加原來(lái)方法的功能
舉個(gè)例子
比如有一個(gè)方法叫 method1()
現(xiàn)在需要在method1調(diào)用的時(shí)候進(jìn)行日志記錄
一般做法是
log()
method1()
但是這樣的問(wèn)題是 所有調(diào)用method1()的地方都要添加log()。多處進(jìn)行更改。
我們需要的是外部的所有調(diào)用還是method1()來(lái)調(diào)用,而method1()執(zhí)行的時(shí)候添加了日志功能,并且還不能更改method1()原來(lái)的代碼。因?yàn)槿绻?code>method1的代碼的話,那么后面如果再需要添加一個(gè)權(quán)限校驗(yàn)功能就又需要改method1的代碼。不符合封閉原則。
這個(gè)時(shí)候就可以用裝飾器模式來(lái)解決這個(gè)問(wèn)題。
下面以Python語(yǔ)言為例
首先需要說(shuō)明的是在Python中,函數(shù)名其實(shí)就是一個(gè)指向函數(shù)體的一個(gè)指針。(應(yīng)該在所有語(yǔ)言中都是這樣的)
即下面這種情況 m2()和method1()是一樣的。都是指向了同一個(gè)方法體
m2 = method1
m2()
如圖所示
那么對(duì)于方法功能擴(kuò)展就可以這樣來(lái)
def w():
def inner():
print('log')
return inner
m = w()
m()
當(dāng)調(diào)用w()時(shí),返回的其實(shí)就是inner函數(shù)的函數(shù)指針
然后m()執(zhí)行,其實(shí)也就是inner()執(zhí)行。所以就輸出log
那么此時(shí)w()這個(gè)函數(shù)和method1還沒(méi)有產(chǎn)生關(guān)系。
現(xiàn)在,我們讓inner執(zhí)行的時(shí)候去執(zhí)行method1
def method1():
print('method1 do something...')
def w(func):
def inner():
print('log')
func()
return inner
m2 = w(method1)
m2()
現(xiàn)在來(lái)解釋一下這段代碼。
首先是method1的定義
然后是一個(gè)w方法的定義,w接受一個(gè)參數(shù)
接下來(lái)調(diào)用w,w將內(nèi)部的inner函數(shù)返回。用m2指向inner函數(shù)
調(diào)用m2也就是調(diào)用inner
inner()函數(shù)執(zhí)行,首先輸出log,然后執(zhí)行func(),這個(gè)func()方法也就是w()傳入的參數(shù)。此處即method1
這樣最終執(zhí)行結(jié)果就是
先調(diào)用日志功能,此處即輸出log
再執(zhí)行method1
但是,外部調(diào)用的method1(),如果像上面這樣需要都改為m2()。我們需要不影響外部調(diào)用 。
如下修改
def method1():
print('method1 do something...')
def w(func):
def inner():
print('log')
func()
return inner
method1 = w(method1)
method1()
我們讓method1重新指向inner函數(shù)的地址
這樣外部所有的調(diào)用還是調(diào)用method1() ,但是該方法已經(jīng)添加了日志功能