意圖
簡(jiǎn)單的說(shuō),命令模式可將“動(dòng)作的請(qǐng)求者”從“動(dòng)作的執(zhí)行者”對(duì)象中解耦。
將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化(即,可以用不同的命令對(duì)象,去參數(shù)化配置客戶的請(qǐng)求);對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志,以及支持可撤銷的操作。
這一模式的關(guān)鍵是一個(gè)抽象的Command類,它定義了一個(gè)執(zhí)行操作的接口。其最簡(jiǎn)單的形式是一個(gè)抽象的Execute操作。具體的Command子類將接收者作為其一個(gè)實(shí)例變量,并實(shí)現(xiàn)Execute操作,指定接收者采取的動(dòng)作。而接收者有執(zhí)行該請(qǐng)求所需的具體信息。
接收者:真正執(zhí)行命令的對(duì)象。任何類都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
結(jié)構(gòu)

-
Command:
定義命令的接口,聲明執(zhí)行的方法。 -
ConcreteCommand:
命令接口實(shí)現(xiàn)對(duì)象,是“虛”的實(shí)現(xiàn);通常會(huì)持有接收者,并調(diào)用接收者的功能來(lái)完成命令要執(zhí)行的操作。 -
Receiver:
接收者,真正執(zhí)行命令的對(duì)象。任何類都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。 -
Invoker:
要求命令對(duì)象執(zhí)行請(qǐng)求,通常會(huì)持有命令對(duì)象,可以持有很多的命令對(duì)象。這個(gè)是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,也就是說(shuō)相當(dāng)于使用命令對(duì)象的入口。 -
Client:
創(chuàng)建具體的命令對(duì)象,并且設(shè)置命令對(duì)象的接收者。注意這個(gè)不是我們常規(guī)意義上的客戶端,而是在組裝命令對(duì)象和接收者,或許,把這個(gè)Client稱為裝配者會(huì)更好理解,因?yàn)檎嬲褂妹畹目蛻舳耸菑腎nvoker來(lái)觸發(fā)執(zhí)行。
流程
a) Client創(chuàng)建一個(gè)ConcreteCommand對(duì)象并指定它的Receiver對(duì)象。
b) 某Invoker對(duì)象存儲(chǔ)該ConcreteCommand對(duì)象。
c) 該Invoker通過(guò)調(diào)用Command對(duì)象的Execute操作來(lái)提交一個(gè)請(qǐng)求。若該命令是可撤銷的,CnocreteCommand就在執(zhí)行Excute操作之前存儲(chǔ)當(dāng)前狀態(tài)以用于取消該命令。
d) ConcreteCommand對(duì)象會(huì)調(diào)用它的Receiver的一些操作以執(zhí)行該請(qǐng)求。
可撤銷的操作
可撤銷操作的意思就是:放棄該操作,回到未執(zhí)行該操作前的狀態(tài)。
有兩種基本的思路來(lái)實(shí)現(xiàn)可撤銷的操作:
① 一種是補(bǔ)償式,又稱反操作式
比如被撤銷的操作是加的功能, 那撤消的實(shí)現(xiàn)就變成減的功能;同理被撤銷的操作是打開(kāi)的功能,那么撤銷的實(shí)現(xiàn)就變成關(guān)閉的功能。
② 另外一種方式是存儲(chǔ)恢復(fù)式
意思就是把操作前的狀態(tài)記錄下來(lái),然后要撤銷操作的時(shí)候就直接恢復(fù)回去就可以了。
認(rèn)識(shí)命令模式
(1)命令模式的關(guān)鍵
命令模式的關(guān)鍵之處就是把請(qǐng)求封裝成為對(duì)象,也就是命令對(duì)象,并定義了統(tǒng)一的執(zhí)行操作的接口,這個(gè)命令對(duì)象可以被存儲(chǔ)、轉(zhuǎn)發(fā)、記錄、處理、撤銷等,整個(gè)命令模式都是圍繞這個(gè)對(duì)象在進(jìn)行。
(2)命令模式的組裝和調(diào)用
在命令模式中經(jīng)常會(huì)有一個(gè)命令的組裝者,用它來(lái)維護(hù)命令的“虛”實(shí)現(xiàn)和真實(shí)實(shí)現(xiàn)之間的關(guān)系。如果是超級(jí)智能的命令,也就是說(shuō)命令對(duì)象自己完全實(shí)現(xiàn)好了,不需要接收者,那就是命令模式的退化,不需要接收者,自然也不需要組裝者了。
而真正的用戶就是具體化請(qǐng)求的內(nèi)容,然后提交請(qǐng)求進(jìn)行觸發(fā)就好了。真正的用戶會(huì)通過(guò)invoker來(lái)觸發(fā)命令。
在實(shí)際開(kāi)發(fā)過(guò)程中,Client和Invoker可以融合在一起,由客戶在使用命令模式的時(shí)候,先進(jìn)行命令對(duì)象和接收者的組裝,組裝完成后,就可以調(diào)用命令執(zhí)行請(qǐng)求。
(3)命令模式的接收者
接收者可以是任意的類,對(duì)它沒(méi)有什么特殊要求,這個(gè)對(duì)象知道如何真正執(zhí)行命令的操作,執(zhí)行時(shí)是從command的實(shí)現(xiàn)類里面轉(zhuǎn)調(diào)過(guò)來(lái)。
一個(gè)接收者對(duì)象可以處理多個(gè)命令,接收者和命令之間沒(méi)有約定的對(duì)應(yīng)關(guān)系。接收者提供的方法個(gè)數(shù)、名稱、功能和命令中的可以不一樣,只要能夠通過(guò)調(diào)用接收者的方法來(lái)實(shí)現(xiàn)命令對(duì)應(yīng)的功能就可以了。
(4)智能命令
在標(biāo)準(zhǔn)的命令模式里面,命令的實(shí)現(xiàn)類是沒(méi)有真正實(shí)現(xiàn)命令要求的功能的,真正執(zhí)行命令的功能的是接收者。
如果命令的實(shí)現(xiàn)對(duì)象比較智能,它自己就能真實(shí)地實(shí)現(xiàn)命令要求的功能,而不再需要調(diào)用接收者,那么這種情況就稱為智能命令。
也可以有半智能的命令,命令對(duì)象知道部分實(shí)現(xiàn),其它的還是需要調(diào)用接收者來(lái)完成,也就是說(shuō)命令的功 能由命令對(duì)象和接收者共同來(lái)完成。
(5)發(fā)起請(qǐng)求的對(duì)象和真正實(shí)現(xiàn)的對(duì)象是解耦的
請(qǐng)求究竟由誰(shuí)處理,如何處理,發(fā)起請(qǐng)求的對(duì)象是不知道的,也就是發(fā)起請(qǐng)求的對(duì)象和真正實(shí)現(xiàn)的對(duì)象是解耦的。發(fā)起請(qǐng)求的對(duì)象只管發(fā)出命令,其它的就不管了。
命令模式的更多用途
命令模式的關(guān)鍵之處就是把請(qǐng)求封裝成為對(duì)象,也就是命令對(duì)象(一個(gè)接收者和一組動(dòng)作),然后將它傳來(lái)傳去,就像是一般的對(duì)象一樣?,F(xiàn)在,即使在命令對(duì)象被創(chuàng)建許久之后,運(yùn)算依然可以被調(diào)用。事實(shí)上,它甚至可以在不同的線程中被調(diào)用。我們可以利用這樣的特性衍生一些應(yīng)用,例如:線程池、工作隊(duì)列、日志請(qǐng)求等。
- 隊(duì)列請(qǐng)求
想象有一個(gè)工作隊(duì)列:你在某一端添加命令,然后另一端則是線程。線程進(jìn)行下面的動(dòng)作:從隊(duì)列中取出一個(gè)命令,調(diào)用它的execute()方法,等待這個(gè)調(diào)用完成,然后將此命令對(duì)象丟棄,再取出下一個(gè)命令......
請(qǐng)注意,工作隊(duì)列和命令對(duì)象之間是完全解耦的。此刻線程可能在進(jìn)行財(cái)務(wù)運(yùn)算,下一刻卻在讀取網(wǎng)絡(luò)數(shù)據(jù)。工作隊(duì)列對(duì)象不在乎到底做些什么,它們只知道取出命令對(duì)象,然后調(diào)用其execute()方法。類似地,它們只要實(shí)現(xiàn)命令模式的對(duì)象,就可以放入隊(duì)列里,當(dāng)線程可用時(shí),就調(diào)用此對(duì)象的execute()方法。 - 日志請(qǐng)求
某些應(yīng)用需要我們將所有的動(dòng)作都記錄在日志中,并能在系統(tǒng)死機(jī)之后,重新調(diào)用這些動(dòng)作恢復(fù)到之前的狀態(tài)。
參考
《Head First 設(shè)計(jì)模式》
《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》
《研磨設(shè)計(jì)模式》