?
在Gof的設(shè)計模式中,有一個模式引起的爭議比較大,有很多人甚至認(rèn)為這個模式應(yīng)該排除在OO模式之外,原因在于它不具有OO的特性。不管怎么說,這個引起爭議的模式還是非常特別的,只要我們靜下心來分析一下,不難發(fā)現(xiàn)它的迷人之處。這個模式就是Command模式。
一、基本的Command模式
最簡單的Command模式中,包含一個ICommand接口,接口只有一個方法Execute。不同的Command對象實現(xiàn)這個接口,客戶端程序通過接口訪問Execute方法的不同實現(xiàn)。

?
好像也沒什么,這個模式太簡單了,幾分鐘就能學(xué)會。
模式本身是簡單的,但模式中包含的思想就不簡單了。有人認(rèn)為Command模式不夠OO的主要原因就是它用OO的思想封裝一個方法,將方法當(dāng)作對象來使用。OO的思想中,所有的名詞都是對象,比如說人;對象有自己的屬性,比如說身高、體重;對象有自己的方法,比如說人會跑,所以有一個Run()的方法。對象、屬性、方法是面向?qū)ο蟮膸状蠡咎卣?。那這個Command模式在搞什么鬼——它居然將方法當(dāng)作對象!太不可理解了,世界上根本就不會有Run這個對象。
Command模式的思想就是模糊了方法與對象的界限。上面說的場景其實可以用下面的方式來實現(xiàn)。

?
其中函數(shù)FunctionA、FunctionB、FunctionC分別對應(yīng)到對象CommandA、CommandB、CommandC。不過采用Command模式比這種方法要更加靈活可變。
二、靜態(tài)分派與動態(tài)分派
分派(Dispatch)可以說是一種定位。不管我們采用什么語言編寫程序,在現(xiàn)在的計算機(jī)體系結(jié)構(gòu)下,代碼最終都會變成函數(shù)調(diào)用。從代碼到具體的函數(shù)調(diào)用這個過程就是分派。
比如說,在圖1中的Client通過ICommand接口調(diào)用具體的Command對象Execute方法。這個過程就是一個分派。不過這個分派是在程序運(yùn)行時才能確定下來,編譯的時候不知道Client將會調(diào)用A、B、C那個對象的方法,只有在運(yùn)行時創(chuàng)建了對象后才知道。
在圖2中的Client直接調(diào)用FunctionA、FunctionB、FunctionC。這個過程也是一個分派。這個分派是編譯器就可以明確下來。
從上面的描述來看,分派有兩種情況:如果分派過程在編譯時就可以確定下來,就叫做靜態(tài)分派,或者叫早綁定;如果分派過程需要在運(yùn)行時才能確定下來,就叫做動態(tài)分派,或者叫做晚綁定。
在C++、Java、C#、Delphi等語言中overload是靜態(tài)的分派,而override是動態(tài)的分派。
上面介紹的Command模式其實是利用override的特性將靜態(tài)的分派轉(zhuǎn)為了動態(tài)的分派,從而帶來更大的靈活性。

?
三、讓靜態(tài)語言“動”起來
很多設(shè)計模式都是因為語言的限制而產(chǎn)生出擴(kuò)充語言表現(xiàn)力的方法。設(shè)計模式會向兩個方面轉(zhuǎn)化:一方面轉(zhuǎn)成語言層面,有些設(shè)計模式就可能直接成為語言的特性,比如說迭代器模式就是如此;另一方面轉(zhuǎn)化成架構(gòu)層面,變成架構(gòu)設(shè)計的基本框架,比如說Facade和Adapter模式。
這篇文章中的Command模式目的也是擴(kuò)充語言的表現(xiàn)力,實現(xiàn)函數(shù)調(diào)用的動態(tài)分派,這樣運(yùn)用設(shè)計模式可以讓我們使用的語言帶有動態(tài)語言的一部分特性。本來動態(tài)語言中的函數(shù)調(diào)用就遠(yuǎn)比常規(guī)語言要靈活得多。
在Gof的設(shè)計模式中,還有一個模式的關(guān)鍵也在于“分派”,就是Visitor模式,這要比Command模式復(fù)雜一些了。大家可以自己看看。等以后有時間我也會寫一篇關(guān)于Visitor的文章。
動態(tài)語言的本質(zhì)就是“晚綁定”,和這里的“動態(tài)分派”有著莫大的關(guān)聯(lián)。我們可以通過設(shè)計模式讓靜態(tài)語言動起來,對于原本就動態(tài)的語言,有些設(shè)計模式可能就沒有意義。
這里分析Command模式僅僅介紹了最基本的情況,對于一些復(fù)雜的變化也并不是動態(tài)語言就可以完全取代的。
四、不能“精通”的語言
精通不管對于什么來說都是非常困難的?!熬笔侵刚莆照Z言本身的特征,能對語言靈活、精確地使用,“通”指的就是觸類旁通,舉一反三。
最開始學(xué)習(xí)編程的時候我們?nèi)W(xué)C++、Java、C#,這個時候只能學(xué)到“精”。等到幾年之后,自認(rèn)為夠“精”了,然后去學(xué)設(shè)計模式,去學(xué)企業(yè)架構(gòu)。這是一般人正常的學(xué)法。但是這樣學(xué)卻不能“精通”語言。就像上面說的,設(shè)計模式又很多會影響到語言,架構(gòu)模式同樣會從語言中的到靈感。
僅僅學(xué)習(xí)語言是不可能精通的,只有學(xué)習(xí)分析、設(shè)計后再和最基本的相互印證才能逐漸領(lǐng)悟到語言的真諦,達(dá)到“精通”吧。
評論