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

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

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

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