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