前言
剛剛看了EuroPython 2017一篇演講,Why You Don't Need Design Patterns in Python,為什么python不用設(shè)計模式。演講者是STXNEXT的Sebastian Buczynski。
他對設(shè)計模式的定義是:
- 常見問題的通用可復(fù)用解決方案
- 定型的最佳實踐
他說設(shè)計模式是一種似曾相識(Anology),是一種大綱(Outline),他認為設(shè)計模式并不是拿來就能用的。
Singleton

第一個是Singleton模式,Singleton的精髓就是任何時候,只有一個類的實例。
《設(shè)計模式》里面給出的Singleton代碼是
聲明:
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
};
實現(xiàn):
Singleton* Singleton::_instance = 0;
Sebastian 在 Google 上面找Singleton的Python實現(xiàn),找到了以下代碼:
聲明:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
實現(xiàn):
one_instance = Singleton()
another_instance = Singleton()
one_instance is another_instance # True
Sebastian指出,照抄C++,當(dāng)然也可以解決問題,但是在python里面有更好的解決方案。比如,可以用@classmethod。不過,最好的解決方案是直接用module。因為module本身就是唯一的,相當(dāng)于module就實現(xiàn)了singleton,那么,我們?yōu)槭裁匆筚M周章,搞一個singleton出來呢?
我回憶了一下,盡管Singleton是最簡單的設(shè)計模式了,但是,我這么多年一直沒用。以前寫C#的時候,我用的是靜態(tài)類,靜態(tài)類本身就是唯一的,所以我不需要singleton。當(dāng)然,我看到有人也用C#寫了和C++一樣的Singleton,但是我覺得解決問題就可以了,沒必要為了寫設(shè)計模式而寫設(shè)計模式。同樣,寫VB.net的時候,我直接用的module,也不需要singleton。
結(jié)論:當(dāng)年《設(shè)計模式》里面的Singleton模式,是為了只有一個類實例。如果編程語言本身,如python, c#, vb.net,已經(jīng)提供了這樣的能力,就沒有必要再用C++的套路了。或者說,設(shè)計模式就不需要了。
Facade


(以上圖片來自參考[1])
Facade的基本概念是,子系統(tǒng)用Facade來屏蔽內(nèi)部的復(fù)雜實現(xiàn)。
這時,我們可以把子系統(tǒng)的python文件統(tǒng)一放在一個文件夾里,然后在這個文件夾里放一個__init__.py文件。

Command
Command模式把請求封裝成對象。
Sebastian認為,在python里面,函數(shù)就是一等公民,所以沒有必要創(chuàng)建對象。
def command(discount_rate):
some_obj.notify_users_about_discount()
也可以用functools創(chuàng)建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里面沒有接口,沒有方法重載。那么怎么實現(xiàn)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
我們看到,這里的實現(xiàn),并沒有class。
Decorator
Decorator可以用來擴展一個對象。
它實現(xiàn)的方法是新建一個類,這個類和原來的類屬于同一個接口。然后這個類接受一個原來的類的對象,每個方法都調(diào)用原來的類的方法。
如果套用c++的《設(shè)計模式》,我們有
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__特性來簡化實現(xiàn)。
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)
總結(jié)
Sebastian指出,python非常靈活。和25年前的C++大相徑庭。很多地方,都非常容易插入邏輯。過去的設(shè)計模式,可能并不適用了。我們應(yīng)該很好的了解python,并借鑒其他語言,而不是生搬硬套。
我覺得,再好的東西,也要和實際相結(jié)合。任何脫離實際的做法,都是多余的,甚至有害的。任何理論,方法的產(chǎn)生,都有當(dāng)時的歷史背景,技術(shù)背景。如果不了解背后的機制,不了解背后的精神和目的,而是專注于招式本身,那只能是越來越僵化。看似堅持,實際上是背叛。堅持是說固執(zhí)的堅持原來的做法,背叛是指背叛了初衷。
參考
[1] Why You Don't Need Design Patterns in Python
[2] Design Patterns – Elements of Reusable Object-Oriented Software
到此這篇關(guān)于詳解Python為什么不用設(shè)計模式的文章就介紹到這了,更多相關(guān)Python設(shè)計模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- python設(shè)計模式大全
- python3 簡單實現(xiàn)組合設(shè)計模式
- python 最簡單的實現(xiàn)適配器設(shè)計模式的示例
- 詳解Python設(shè)計模式之策略模式
- PageFactory設(shè)計模式基于python實現(xiàn)
- python單例設(shè)計模式實現(xiàn)解析
- Python PO設(shè)計模式的具體使用