詳解Python為什麼不用設計模式
前言
剛剛看瞭EuroPython 2017一篇演講,Why You Don’t Need Design Patterns in Python,為什麼python不用設計模式。演講者是STXNEXT的Sebastian Buczynski。
他對設計模式的定義是:
- 常見問題的通用可復用解決方案
- 定型的最佳實踐
他說設計模式是一種似曾相識(Anology),是一種大綱(Outline),他認為設計模式並不是拿來就能用的。
Singleton
第一個是Singleton模式,Singleton的精髓就是任何時候,隻有一個類的實例。
《設計模式》裡面給出的Singleton代碼是
聲明:
class Singleton { public: static Singleton* Instance(); protected: Singleton(); private: static Singleton* _instance; };
實現:
Singleton* Singleton::_instance = 0;
Sebastian 在 Google 上面找Singleton的Python實現,找到瞭以下代碼:
聲明:
class Singleton: _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance
實現:
one_instance = Singleton() another_instance = Singleton() one_instance is another_instance # True
Sebastian指出,照抄C++,當然也可以解決問題,但是在python裡面有更好的解決方案。比如,可以用@classmethod。不過,最好的解決方案是直接用module。因為module本身就是唯一的,相當於module就實現瞭singleton,那麼,我們為什麼要大費周章,搞一個singleton出來呢?
我回憶瞭一下,盡管Singleton是最簡單的設計模式瞭,但是,我這麼多年一直沒用。以前寫C#的時候,我用的是靜態類,靜態類本身就是唯一的,所以我不需要singleton。當然,我看到有人也用C#寫瞭和C++一樣的Singleton,但是我覺得解決問題就可以瞭,沒必要為瞭寫設計模式而寫設計模式。同樣,寫VB.net的時候,我直接用的module,也不需要singleton。
結論:當年《設計模式》裡面的Singleton模式,是為瞭隻有一個類實例。如果編程語言本身,如python, c#, vb.net,已經提供瞭這樣的能力,就沒有必要再用C++的套路瞭。或者說,設計模式就不需要瞭。
Facade
(以上圖片來自參考[1])
Facade的基本概念是,子系統用Facade來屏蔽內部的復雜實現。
這時,我們可以把子系統的python文件統一放在一個文件夾裡,然後在這個文件夾裡放一個__init__.py文件。
Command
Command模式把請求封裝成對象。
Sebastian認為,在python裡面,函數就是一等公民,所以沒有必要創建對象。
def command(discount_rate): some_obj.notify_users_about_discount()
也可以用functools創建command
import functools command = functools.partial( some_obj.notify_users_about_discount, discount_rate=0.5 ) command() # equals to some_obj.notify_users_about_discount(discount_rate=0.5)
Visitor
Python裡面沒有接口,沒有方法重載。那麼怎麼實現Visitor呢?
Sebastian指出,可以用@SingleDispatch。
from functools import singledispatch @singledispatch def visit(node): type_name = type(node).__name__ raise AttributeError(f'No handler found for {type_name}')
from ast_nodes import Assign, FunctionDef @visit.register(Assign) def visit(node): pass @visit.register(FunctionDef) def visit(node): pass
我們看到,這裡的實現,並沒有class。
Decorator
Decorator可以用來擴展一個對象。
它實現的方法是新建一個類,這個類和原來的類屬於同一個接口。然後這個類接受一個原來的類的對象,每個方法都調用原來的類的方法。
如果套用c++的《設計模式》,我們有
class OriginalClass: def get_text(self): pass def get_number(self): pass class Decorator: def __init__(self, decorated_obj): self.decorated_obj = decorated_obj def get_text(self): return f'<b>{self.decorated_obj.get_text()}</b>' def get_number(self): return self.decorated_obj.get_number()
但是,這裡可以用python的__getattr__特性來簡化實現。
class Decorator: def __init__(self, decorated_obj): self.decorated_obj = decorated_obj def get_text(self): return f'{self.decorated_obj.get_text()}' def __getattr__(self, attr_name): return getattr(self.decorated_obj, attr_name)
總結
Sebastian指出,python非常靈活。和25年前的C++大相徑庭。很多地方,都非常容易插入邏輯。過去的設計模式,可能並不適用瞭。我們應該很好的瞭解python,並借鑒其他語言,而不是生搬硬套。
我覺得,再好的東西,也要和實際相結合。任何脫離實際的做法,都是多餘的,甚至有害的。任何理論,方法的產生,都有當時的歷史背景,技術背景。如果不瞭解背後的機制,不瞭解背後的精神和目的,而是專註於招式本身,那隻能是越來越僵化。看似堅持,實際上是背叛。堅持是說固執的堅持原來的做法,背叛是指背叛瞭初衷。
參考
[1] Why You Don’t Need Design Patterns in Python
[2] Design Patterns – Elements of Reusable Object-Oriented Software
到此這篇關於詳解Python為什麼不用設計模式的文章就介紹到這瞭,更多相關Python設計模式內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!