Java 设计模式之命令模式
一、了解命令模式
1.1 什么是命令模式
命令模式將“請(qǐng)求”封裝成對(duì)象,以便使用不同的請(qǐng)求、隊(duì)列或者日志來(lái)參數(shù)化其他對(duì)象。命令模式也支持可撤銷(xiāo)的操作。這種說(shuō)法比較難以理解,換種說(shuō)法就是指:
在軟件系統(tǒng)中,“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”通常呈現(xiàn)一種“緊耦合”。但在某些場(chǎng)合,比如要對(duì)行為進(jìn)行“記錄、撤銷(xiāo)/重做、事務(wù)”等處理,這種無(wú)法抵御變化的緊耦合是不合適的。
在這種情況下,如何將“行為請(qǐng)求者”與“行為實(shí)現(xiàn)者”解耦?將一組行為抽象為對(duì)象,實(shí)現(xiàn)二者之間的松耦合。這就是命令模式(Command Pattern)。
1.2 命令模式組成結(jié)構(gòu)
- 命令接口 (Command):定義命令的接口,聲明執(zhí)行的方法。
- 具體命令 (ConcreteCommand):命令接口實(shí)現(xiàn)對(duì)象,是“虛”的實(shí)現(xiàn);通常會(huì)持有接收者,并調(diào)用接收者的功能來(lái)完成命令要執(zhí)行的操作。
- 接受者 (Receiver):接收者,真正執(zhí)行命令的對(duì)象。任何類(lèi)都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
- 調(diào)用者 (Invoker):要求命令對(duì)象執(zhí)行請(qǐng)求,通常會(huì)持有命令對(duì)象,可以持有很多的命令對(duì)象。這個(gè)是客戶(hù)端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,也就是說(shuō)相當(dāng)于使用命令對(duì)象的入口。
- 客戶(hù) (Client):創(chuàng)建具體的命令對(duì)象,并且設(shè)置命令對(duì)象的接收者。注意這個(gè)不是我們常規(guī)意義上的客戶(hù)端,而是在組裝命令對(duì)象和接收者,或許,把這個(gè) Client 稱(chēng)為裝配者會(huì)更好理解,因?yàn)檎嬲褂妹畹目蛻?hù)端是從 Invoker 來(lái)觸發(fā)執(zhí)行。
1.3 命令模式 UML 圖解
1.4 命令模式適用場(chǎng)景
- 系統(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)需要將一組操作組合在一起,即支持宏命令。
二、命令模式具體應(yīng)用
2.1 問(wèn)題描述
電燈遙控器:現(xiàn)在讓你為一種新型電燈設(shè)計(jì)一種手持的遠(yuǎn)程遙控器,這個(gè)遙控器可以打開(kāi)和關(guān)閉電燈。
2.2 問(wèn)題分析設(shè)計(jì)設(shè)計(jì)圖
2.3 代碼實(shí)現(xiàn)
接收者 Light 類(lèi)
package com.jas.command; /*** 電燈提供打開(kāi)和關(guān)閉的功能*/ public class Light {void on(){System.out.println("Light is on!");}void off(){ System.out.println("Light is off!"); } }命令接口 Command
package com.jas.command; /*** 所有的命令對(duì)象都應(yīng)該實(shí)現(xiàn)的接口,提供了一個(gè)執(zhí)行的方法。*/ public interface Command {void execute(); }具體命令 LightOnCommand 類(lèi)
package com.jas.command;public class LightOnCommand implements Command {Light light;/*** 通過(guò)構(gòu)造器實(shí)力化 light 對(duì)象,在 execute() 方法中調(diào)用其對(duì)應(yīng)的打開(kāi)與關(guān)閉方法* * @param light 電燈對(duì)象*/public LightOnCommand(Light light){this.light = light;}/*** 調(diào)用電燈打開(kāi)的方法*/@Overridepublic void execute() {light.on();} }具體命令 LightOffCommand 類(lèi)
package com.jas.command;public class LightOffCommand implements Command {Light light;public LightOffCommand(Light light){this.light = light;}/*** 調(diào)用電燈關(guān)閉的方法*/@Overridepublic void execute() {light.off();} }調(diào)用者 RemoteControl 類(lèi) (遙控器)
package com.jas.command;public class RemoteControl {Command onCommand;Command offComand;public RemoteControl(){}/*** 傳入一組命令* * @param onCommand 打開(kāi)電燈的命令對(duì)象* @param offComand 關(guān)閉電燈的命令對(duì)象*/public void setCommand(Command onCommand, Command offComand){this.onCommand = onCommand;this.offComand = offComand;}/*** 打開(kāi)電燈的按鈕,通過(guò) onCommand 調(diào)用 execute() 方法*/public void onButtonWasPushed(){//execute() 方法中封裝了打開(kāi)電燈的方法onCommand.execute();}/*** 關(guān)閉電燈的按鈕,通過(guò) offComand 調(diào)用 execute() 方法*/public void offButtonWasPushed(){//execute() 方法中封裝了關(guān)閉電燈的方法offComand.execute();} }客戶(hù) RemoteLoader 類(lèi)
package com.jas.command;public class RemoteLoader {public static void main(String[] args) {// 定義一個(gè)遠(yuǎn)程遙控器RemoteControl remoteControl = new RemoteControl();// 定義一個(gè)電燈對(duì)象Light light = new Light();// 打開(kāi)電燈的命令對(duì)象Command onCommand = new LightOnCommand(light);// 關(guān)閉電燈的命令對(duì)象Command offCommand = new LightOffCommand(light);remoteControl.setCommand(onCommand,offCommand);remoteControl.onButtonWasPushed();remoteControl.offButtonWasPushed();} }/*** 輸出* Light is on!* Light is off!*/三、命令模式總結(jié)
3.1 命令模式優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 降低對(duì)象之間的耦合度。
- 新的命令可以很容易地加入到系統(tǒng)中。
- 可以比較容易地設(shè)計(jì)一個(gè)組合命令。
- 調(diào)用同一方法實(shí)現(xiàn)不同的功能。
缺點(diǎn)
使用命令模式可能會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類(lèi)。因?yàn)獒槍?duì)每一個(gè)命令都需要設(shè)計(jì)一個(gè)具體命令類(lèi),因此某些系統(tǒng)可能需要大量具體命令類(lèi),這將影響命令模式的使用。
3.2 命令模式知識(shí)點(diǎn)總結(jié)
PS:可以參考上面的例子進(jìn)行知識(shí)回顧加深。
- 命令模式將發(fā)出請(qǐng)求的對(duì)象和執(zhí)行請(qǐng)求的對(duì)象解耦。
- 在被解耦的兩者之間是通過(guò)命令對(duì)象進(jìn)行溝通的。命令對(duì)象封裝了具體接收者和一個(gè)或一組動(dòng)作。
- 調(diào)用者通過(guò)命令對(duì)象的 execute() 發(fā)出請(qǐng)求,這會(huì)使接收者的動(dòng)作被調(diào)用。
- 調(diào)用者可以接收命令對(duì)象當(dāng)做參數(shù),甚至是在運(yùn)行時(shí)動(dòng)態(tài)的進(jìn)行。
- 命令可以支持撤銷(xiāo) (undo),做法是實(shí)現(xiàn)一個(gè) undo() 方法,可以回到 execute() 方法執(zhí)行前的狀態(tài)。
- 命令也可以用來(lái)實(shí)現(xiàn)日志和系統(tǒng)事務(wù)。
PS:點(diǎn)擊了解更多設(shè)計(jì)模式 http://blog.csdn.net/codejas/article/details/79236013
參考文獻(xiàn)
《Head First 設(shè)計(jì)模式》
總結(jié)
以上是生活随笔為你收集整理的Java 设计模式之命令模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 寓意好的网名
- 下一篇: 2020年12月28号出生的女孩取什么名