1. 命令模式
1.1 簡(jiǎn)介
??命令模式(Command Pattern)是一種數(shù)據(jù)驅(qū)動(dòng)的設(shè)計(jì)模式,它屬于行為型模式究履。請(qǐng)求以命令的形式包裹在對(duì)象中滤否,并傳給調(diào)用對(duì)象。調(diào)用對(duì)象尋找可以處理該命令的合適的對(duì)象最仑,并把該命令傳給相應(yīng)的對(duì)象藐俺,該對(duì)象執(zhí)行命令炊甲。
??將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓你使用不同的請(qǐng)求把客戶端參數(shù)化欲芹,對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志卿啡,可以提供命令的撤銷(xiāo)和恢復(fù)功能。 (來(lái)自《設(shè)計(jì)模式之禪》)
1.2 結(jié)構(gòu)
Command模式uml:
Command模式角色:
- Command:定義命令的接口菱父,聲明執(zhí)行的方法颈娜。
- ConcreteCommand: 具體的命令, 實(shí)現(xiàn)命令接口浙宜;通常會(huì)持有接收者官辽,并調(diào)用接收者的功能來(lái)完成命令要執(zhí)行的操作。
- Receiver:接收者粟瞬,真正執(zhí)行命令的對(duì)象同仆。任何類(lèi)都可能成為一個(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稱(chēng)為裝配者會(huì)更好理解,因?yàn)檎嬲褂妹畹目蛻舳耸菑腎nvoker來(lái)觸發(fā)執(zhí)行揩懒。
2. 示例
??司令員下令讓士兵去干件事情什乙,從整個(gè)事情的角度來(lái)考慮,司令員的作用是已球,發(fā)出口令臣镣,口令經(jīng)過(guò)傳遞,傳到了士兵耳朵里智亮,士兵去執(zhí)行忆某。這個(gè)過(guò)程好在,三者相互解耦阔蛉,任何一方都不用去依賴(lài)其他人弃舒,只需要做好自己的事兒就行,司令員要的是結(jié)果,不會(huì)去關(guān)注到底士兵是怎么實(shí)現(xiàn)的聋呢。
??Invoker是調(diào)用者(司令員)苗踪,Receiver是被調(diào)用者(士兵),MyCommand是命令削锰,實(shí)現(xiàn)了Command接口通铲,持有接收對(duì)象。
** Command:**
public interface Command {
public void exe();
}
** MyCommand:**
public class MyCommand implements Command {
private Receiver receiver;
public MyCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void exe() {
receiver.action();
}
}
** Receiver:**
public class Receiver {
public void action(){
System.out.println("command received!");
}
}
** Invoker:**
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action(){
command.exe();
}
}
** 調(diào)用示例:**
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command cmd = new MyCommand(receiver);
Invoker invoker = new Invoker(cmd);
invoker.action();
}
3. 總結(jié)
??命令模式的目的就是達(dá)到命令的發(fā)出者和執(zhí)行者之間解耦器贩,實(shí)現(xiàn)請(qǐng)求和執(zhí)行分開(kāi)颅夺,熟悉Struts的同學(xué)應(yīng)該知道,Struts其實(shí)就是一種將請(qǐng)求和呈現(xiàn)分離的技術(shù)蛹稍,其中必然涉及命令模式的思想吧黄!
命令模式優(yōu)點(diǎn):
- 降低了系統(tǒng)耦合度。
- 命令模式的封裝性很好:每個(gè)命令都被封裝起來(lái)唆姐,對(duì)于客戶端來(lái)說(shuō)稚字,需要什么功能就去調(diào)用相應(yīng)的命令,而無(wú)需知道命令具體是怎么執(zhí)行的厦酬。比如有一組文件操作的命令:新建文件、復(fù)制文件瘫想、刪除文件仗阅。如果把這三個(gè)操作都封裝成一個(gè)命令類(lèi),客戶端只需要知道有這三個(gè)命令類(lèi)即可国夜,至于命令類(lèi)中封裝好的邏輯减噪,客戶端則無(wú)需知道。
- 命令模式的擴(kuò)展性很好车吹,在命令模式中筹裕,在接收者類(lèi)中一般會(huì)對(duì)操作進(jìn)行最基本的封裝,命令類(lèi)則通過(guò)對(duì)這些基本的操作進(jìn)行二次封裝窄驹,當(dāng)增加新命令的時(shí)候朝卒,對(duì)命令類(lèi)的編寫(xiě)一般不是從零開(kāi)始的,有大量的接收者類(lèi)可供調(diào)用乐埠,也有大量的命令類(lèi)可供調(diào)用抗斤,代碼的復(fù)用性很好。比如丈咐,文件的操作中瑞眼,我們需要增加一個(gè)剪切文件的命令,則只需要把復(fù)制文件和刪除文件這兩個(gè)命令組合一下就行了棵逊,非常方便伤疙。
- 可以實(shí)現(xiàn)宏命令。命令模式可以與組合模式結(jié)合辆影,將多個(gè)命令裝配成一個(gè)組合命令徒像,即宏命令黍特。
- 方便實(shí)現(xiàn) Undo 和 Redo 操作。命令模式可以與后面介紹的備忘錄模式結(jié)合厨姚,實(shí)現(xiàn)命令的撤銷(xiāo)與恢復(fù)衅澈。
- 增加或刪除命令非常方便。采用命令模式增加與刪除命令不會(huì)影響其他類(lèi)谬墙,它滿足“開(kāi)閉原則”今布,對(duì)擴(kuò)展比較靈活。
命令模式缺點(diǎn):
- 使用命令模式可能會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類(lèi)拭抬。因?yàn)獒槍?duì)每一個(gè)命令都需要設(shè)計(jì)一個(gè)具體命令類(lèi)部默,因此某些系統(tǒng)可能需要大量具體命令類(lèi),這將影響命令模式的使用造虎。
命令模式適用場(chǎng)景:
- struts 1 中的 action 核心控制器 ActionServlet 只有一個(gè)傅蹂,相當(dāng)于 Invoker,而模型層的類(lèi)會(huì)隨著不同的應(yīng)用有不同的模型類(lèi)算凿,相當(dāng)于具體的 Command份蝴。
- 系統(tǒng)需要將請(qǐng)求調(diào)用者和請(qǐng)求接收者解耦,使得調(diào)用者和接收者不直接交互氓轰。
- 系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求婚夫、將請(qǐng)求排隊(duì)和執(zhí)行請(qǐng)求。
- 系統(tǒng)需要支持命令的撤銷(xiāo)(Undo)操作和恢復(fù)(Redo)操作署鸡。
- 系統(tǒng)需要將一組操作組合在一起案糙,即支持宏命令。