1、所有書中都沒有把猴子補丁作為一種設計模式來看待。因為設計模式的模式的命名是根據java中提煉出來的,語言方式決定了java絕對不會有也不需要有這種操作,不存在的。那自然設計模式不會包括猴子補丁模式。
2、根據百度百科介紹,設計模式(Design pattern)代表了最佳的實踐,通常被有經驗的面向對象的軟件開發人員所采用。設計模式是軟件開發人員在軟件開發過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發人員經過相當長的一段時間的試驗和錯誤總結出來的。只要是解決高可擴展和高可復用的編碼問題就可以算是一種設計模式,猴子補丁是在python里面一種很普遍達到這種目的方式,所以可以算是一種設計模式。
3、在python 函數和類和全局變量都是一等公民,不是所有東西必須都要寫到一個類里面包裹起來,寫起來很自由。有的python人員c語言中毒太深或者連c語言都沒學過只自學python,寫代碼項目里面永遠只會有0個類(除開文檔上規定死了要寫一個類的這種類),模塊加函數的寫法只能解決局部復用,和類的可復用性相比差距很大。但是別人就是打死也不願意項目里面有一個類出現,這種情況怎么改造這個模塊的整體功能?
假設有個文件叫 xxx.py, 且xxx.py代碼如下:
_var_aaa = 1
def _function_bbb(paramx):
return paramx * 10
def function_ccc(paramx):
print(_var_aaa) # 這里假設是print,實際肯定是拿着var_aaa變量做實際有意義的事情
_function_bbb(paramx)
do_othrething() ................................
模塊的function_ccc函數是唯一 作為公有函數,是希望被外界調用的。但這個函數很蛋疼,依賴了模塊/包 里面的外部變量和外部函數,要改他並不是改這個函數本身就能達到目的,還要改其他地方。
假如希望全局變量 _var_aaa的初始值是2,函數_function_bbb的功能是吧變量擴大100倍,怎么改?
1)、去修改源文件,肯定不靠譜,你硬編碼的方式改了這里的代碼,如果沒通知別人,別人繼續使用,別人調用函數會出來新的結果會出毛病。而且猴子補丁很多時候是針對三方包或者官方包,去直接修改那些地方的文件很不靠譜,任何時候都不要這么做。
2)、把整個包/模塊復制出來一份,然后修改其中的一小部分幾行代碼,殺雞用牛刀,為了0.01%代碼的改變,無緣無故增加幾千幾萬行相同字母的代碼。
以上兩種方法都不好,在最小代價下實現 全局變量 _var_aaa的初始值是2,函數__function_bbb的功能是吧變量擴大100倍,應該就是輪到猴子補丁上場了,
import xxx
xxx._var_aaa = 2
def _my_function_bbb(paramx):
return paramx * 100
xxx._function_bbb = _my_function_bbb
之后再次調用 function_ccc,就會使改變生效了,不止當前代碼模塊處會生效,運行patch后會使所有地方生效。
猴子補丁賴以實現的基礎是
python 模塊會導入幾次?猴子補丁為什么可以實現?
4、 最好還是使用面向對象來編程。猴子補丁模式雖靈活,猴子補丁是在之前擴展沒設計好的基礎上才不得已為之才使用的。用起來很多弊端,比如pycharm智能提示和跳轉支持很差,因為是在運行時后改變行為的,pycahrm是死的只會根據固定的代碼結構進行智能提示和補全,不會去猜測運行時候的行為。模塊始終是個單例,一會兒想var_aaa初始變量是3一會希望他是2,一會希望function_bbb的功能是擴大一百倍一會兒希望他是擴大一萬倍,猴子補丁是無法實現得,使用面oop這些問題是非常輕松非常正常自然的完成的,完全不需要想。因為類可以繼承,模塊無法繼承;類是多實例的(每個實例就像無數復制出來的內部屬性互不干擾的模塊),不會像模塊一樣只有一份。
5、自己寫的代碼最好設計好擴展使用oop,不要讓自己的模塊有被別人打猴子補丁的想法和機會。讓打猴子補丁只發生在修改三方包和官方包的時候,如果自己寫的代碼也需要大猴子補丁才能實現改造,那應該是沒設計好,沒有暴露出使用策略/模板方法。
6、關於面向過程和面向對象編程,介紹了很多次區別,和oop的優點。我絕對沒說過所有場景所有地方都要全100%使用純oop,但我反對那些不管任何情況都堅持代碼只有0個類的寫法,這種寫法情況的人現實和網上見過很多。多試下多對比下才能知道體會到區別,不然老是籠統的二逼的說法就是大項目用oop小項目用ofp當擋箭牌。具體多大才算大?200行代碼不算大嗎,每次新做項目功能時候把自己的200行代碼復制黏貼扣字修改反復弄幾百次也算200行嗎?大項目也不可能純100%oop,會兩樣都有。
要知道什么時候使用oop,而不是數代碼的行數再來決定使不使用oop,比如8種方法實現寫計數器例子,實現計數器總共才不到10行,寫閉包函數明顯比使用類更晦澀難懂,難道行數少就適合函數嗎?大項目也不是所有函數都需要改成方法包裹在類里面。
到底是用哪一種,一個判斷是函數如果是非常孤立的,不依賴外部狀態和依賴的外部函數不可能需要改變,比如單獨做個時間格式轉換,用函數沒毛病,放在大項目也可以。
如果函數有一些依賴,特別是依賴的屬性和函數需要彈性改變,使用類好。
據我的實踐,我使用oop改造了項目里面的很多模塊或者子任務,基本上每次使用oop重構都能夠比原有的opp代碼減少40%-90%的代碼行數。