Java设计模式之行为型:命令模式
前言:
????????在開(kāi)發(fā)中,我們可能需要向某些對(duì)象發(fā)送一些請(qǐng)求,但我們不知道請(qǐng)求的具體接收者是誰(shuí),也不知道被請(qǐng)求的操作是哪個(gè),只知道在系統(tǒng)運(yùn)行中指定具體的請(qǐng)求接收者即可,打個(gè)比方,電視遙控器,我們只需知道按哪個(gè)按鈕能夠打開(kāi)電視、關(guān)閉電視和換臺(tái)即可,并不需要知道是怎么開(kāi)電視、關(guān)電視和換臺(tái)的,對(duì)于這種情況,我們可以采用命令模式來(lái)進(jìn)行設(shè)計(jì)。
一、定義:
????????命令模式的本質(zhì)是將請(qǐng)求封裝成對(duì)象,將發(fā)出命令與執(zhí)行命令的責(zé)任分開(kāi),命令的發(fā)送者和接收者完全解耦,發(fā)送者只需知道如何發(fā)送命令,不需要關(guān)心命令是如何實(shí)現(xiàn)的,甚至是否執(zhí)行成功都不需要理會(huì)。命令模式的關(guān)鍵在于引入了抽象命令接口,發(fā)送者針對(duì)抽象命令接口編程,只有實(shí)現(xiàn)了抽象命令接口的具體命令才能與接收者相關(guān)聯(lián)。另外命令可以像強(qiáng)對(duì)象一樣可以被存儲(chǔ)和傳遞,所以可支持撤銷(xiāo)的操作
? ? ? ? 使用命令模式的優(yōu)勢(shì)在于降低了系統(tǒng)的耦合度,而且新命令可以很方便添加到系統(tǒng)中,也容易設(shè)計(jì)一個(gè)組合命令。但缺點(diǎn)在于會(huì)導(dǎo)致某些系統(tǒng)有過(guò)多的具體命令類(lèi),因?yàn)獒槍?duì)每一個(gè)命令都需要設(shè)計(jì)一個(gè)具體命令類(lèi)。所以命令模式適用于以下場(chǎng)景:
- (1)需要將請(qǐng)求調(diào)用者和請(qǐng)求接收者解耦,使得調(diào)用者和接收者不直接交互。
- (2)系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)和執(zhí)行請(qǐng)求。
- (3)系統(tǒng)需要支持命令的撤銷(xiāo)(Undo)操作和恢復(fù)(Redo)操作。
- (4)系統(tǒng)需要將一組操作組合在一起,即支持宏命令。
二、UML結(jié)構(gòu)圖:
- Receiver:接收者,執(zhí)行命令的對(duì)象,任何類(lèi)都可能成為一個(gè)接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
- Command:抽象命令類(lèi),聲明需要執(zhí)行的方法。
- ConcreteCommand:具體命令類(lèi),通常會(huì)持有接收者,并調(diào)用接收者的功能完成命令要執(zhí)行的操作。
- Invoker:調(diào)用者,通常會(huì)持有命令對(duì)象,可以持有多個(gè)命令對(duì)象,是客戶(hù)端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,就是相當(dāng)于使用命令對(duì)象的入口。
- Client:客戶(hù)類(lèi),創(chuàng)建具體的命令對(duì)象,并且設(shè)置命令對(duì)象的接收者。注意這里不是指常規(guī)意義上的客戶(hù)端,把這個(gè) Client 稱(chēng)為裝配者會(huì)合適,主要用于組裝命令對(duì)象和接收者。
三、代碼實(shí)現(xiàn):
????????這里以電視機(jī)為例。電視是請(qǐng)求的接受者,遙控器是請(qǐng)求的發(fā)送者,遙控器上有一些按鈕,不同的按鈕對(duì)應(yīng)著不同的操作。在這里遙控器需要執(zhí)行三個(gè)命令:打開(kāi)電視機(jī)、關(guān)閉電視機(jī)、換臺(tái)。UML類(lèi)圖如下:
抽象命令類(lèi):Command.java
/*** Command命令接口,為所有的命令聲明一個(gè)接口。所有的命令都應(yīng)該實(shí)現(xiàn)它*/ public interface Command {public void execute(); }電視機(jī)類(lèi):Television.java
public class Television {public void open(){System.out.println("打開(kāi)電視機(jī)......");}public void close(){System.out.println("關(guān)閉電視機(jī)......"); }public void changeChannel(){System.out.println("切換電視頻道......");} }遙控器類(lèi):Controller.java
public class Controller {private Command openTVCommand;private Command closeTVCommand;private Command changeChannelCommand;public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){this.openTVCommand = openTvCommand;this.closeTVCommand = closeTvCommand;this.changeChannelCommand = changeChannelCommand;}/*** 打開(kāi)電視劇*/public void open(){openTVCommand.execute();}/*** 關(guān)閉電視機(jī)*/public void close(){closeTVCommand.execute();}/*** 換頻道*/public void change(){changeChannelCommand.execute();} }?遙控器的三個(gè)按鈕:
public class OpenTvCommand implements Command{private Television tv;public OpenTvCommand(Television tv){this.tv = tv;}public void execute() {tv.open();} } public class ChangeChannelCommand implements Command{private Television tv;public ChangeChannelCommand(Television tv){this.tv = tv;}public void execute() {tv.changeChannel();} } public class CloseTvCommand implements Command{private Television tv;public CloseTvCommand(Television tv){this.tv = tv;}public void execute() {tv.close();} }客戶(hù)端:Client.java
public class Client {public static void main(String a[]){Television tv = new Television();Command openCommand,closeCommand,changeCommand;openCommand = new OpenTvCommand(tv);closeCommand = new CloseTvCommand(tv);changeCommand = new ChangeChannelCommand(tv);Controller control = new Controller(openCommand,closeCommand,changeCommand);control.open(); //打開(kāi)電視機(jī)control.change(); //換頻道control.close(); //關(guān)閉電視機(jī)} }運(yùn)行結(jié)果:
打開(kāi)電視機(jī)...... 切換電視機(jī)頻道...... 關(guān)閉電視機(jī)......命令模式擴(kuò)展:前面說(shuō)過(guò),命令模式支持撤銷(xiāo)命令:在電視遙控器中,我們還有這樣一個(gè)按鈕,那就是返回。用于切換到上面一個(gè)頻道中去。在命令模式中也支持撤銷(xiāo)操作,在這里我們只需要記錄上一個(gè)頻道,然后將上一個(gè)頻道傳入即可。在這里將 Command 進(jìn)行一個(gè)簡(jiǎn)單的修改:將 execute() 改為 execute(int i);? i表示頻道,用于進(jìn)行頻道切換。
/*** Command命令接口,為所有的命令聲明一個(gè)接口。所有的命令都應(yīng)該實(shí)現(xiàn)它*/ public interface Command {/*** 為了方便切換頻道,這里使用參數(shù)i將頻道傳遞* @param i*/public void execute(int i); }?然后在Controller中添加channelUndo()方法,用于進(jìn)行頻道返回。并且需要進(jìn)行一些簡(jiǎn)單的修改。
public class Controller {private Command openTVCommand;private Command closeTVCommand;private Command changeChannelCommand;public int nowChannel = 0; //當(dāng)前頻道public int priorChannel; //前一個(gè)頻道,用于執(zhí)行返回操作public Controller(Command openTvCommand,Command closeTvCommand,Command changeChannelCommand){this.openTVCommand = openTvCommand;this.closeTVCommand = closeTvCommand;this.changeChannelCommand = changeChannelCommand;}/*** 打開(kāi)電視劇*/public void open(){openTVCommand.execute(0);}/*** 關(guān)閉電視機(jī)*/public void close(){closeTVCommand.execute(0);}/*** 換頻道:只在當(dāng)前頻道遞增*/public void change(){priorChannel = nowChannel; //換頻道前記錄當(dāng)前頻道nowChannel++; //頻道+1changeChannelCommand.execute(nowChannel);}/*** 頻道返回*/public void ChannelUndo(){changeChannelCommand.execute(priorChannel); //將以前的頻道傳入//當(dāng)前頻道與前一個(gè)頻道進(jìn)行互換int tempChannel;tempChannel = priorChannel;priorChannel = nowChannel;nowChannel = tempChannel;} }客戶(hù)端:
public class Client {public static void main(String a[]){Television tv = new Television();Command openCommand,closeCommand,changeCommand;openCommand = new OpenTvCommand(tv);closeCommand = new CloseTvCommand(tv);changeCommand = new ChangeChannelCommand(tv);Controller control = new Controller(openCommand,closeCommand,changeCommand);control.open(); //打開(kāi)電視機(jī)control.change(); //換頻道control.change();control.ChannelUndo();control.ChannelUndo();control.ChannelUndo();control.close(); //關(guān)閉電視機(jī)} }運(yùn)行結(jié)果:
設(shè)計(jì)模式系列文章:
Java設(shè)計(jì)模式之創(chuàng)建型:工廠(chǎng)模式詳解(簡(jiǎn)單工廠(chǎng)+工廠(chǎng)方法+抽象工廠(chǎng))
Java設(shè)計(jì)模式之創(chuàng)建型:建造者模式
Java設(shè)計(jì)模式之創(chuàng)建型:單例模式
Java設(shè)計(jì)模式之創(chuàng)建型:原型模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:適配器模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:裝飾器模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:代理模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:橋接模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:外觀模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:組合模式
Java設(shè)計(jì)模式之結(jié)構(gòu)型:享元模式
Java設(shè)計(jì)模式之行為型:策略模式
Java設(shè)計(jì)模式之行為型:模板方法模式
Java設(shè)計(jì)模式之行為型:責(zé)任鏈模式
Java設(shè)計(jì)模式之行為型:觀察者模式
Java設(shè)計(jì)模式之行為型:訪(fǎng)問(wèn)者模式
Java設(shè)計(jì)模式之行為型:中介者模式
Java設(shè)計(jì)模式之行為型:命令模式
Java設(shè)計(jì)模式之行為型:狀態(tài)模式
Java設(shè)計(jì)模式之行為型:備忘錄模式
Java設(shè)計(jì)模式之行為型:迭代器模式
Java設(shè)計(jì)模式之行為型:解釋器模式
參考文章:設(shè)計(jì)模式讀書(shū)筆記-----命令模式_chenssy 的技術(shù)博客-CSDN博客
與50位技術(shù)專(zhuān)家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Java设计模式之行为型:命令模式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java设计模式之行为型:责任链模式
- 下一篇: Java设计模式之行为型:备忘录模式