一起学设计模式 - 命令模式
命令模式(Command Pattern)屬于行為型模式的一種,又稱為行動(Action)模式或交易(Transaction)模式。將一個請求封裝為一個對象,從而達到用不同的請求對客戶進行參數化,對于排隊請求或請求日志記錄,可以提供命令的撤銷和恢復功能。
<!-- more -->
概述
命令模式:對命令的封裝,把發送命令和執行命令的責任分割開,分別委派給不同的對象,每一個命令都是一個操作,允許請求方與接收方獨立開來,使之請求方不必清楚接收方的接口,更不必知道請求是怎么被接收,以及操作是否被執行、何時被執行,以及是怎么被執行的。
UML結構圖
模式結構
- Command(抽象命令類): 聲明了用于執行請求的的exceute()等方法
- ConcreteCommand(具體命令類): 抽象命令類的子類,對應具體的接收者對象,將接收者對象的動作綁定其中。在實現execute()方
法時,將調用接收者對象的相關操作(Action)。
- Invoker(調用者): 調用命令對象執行請求,相關的方法叫做行動方法。
- Receiver(接收者): 負責具體實施和執行一個請求。任何一個類都可以成為接收者,實施和執行請求的方法叫做行動方法。
案例
博主比較喜歡聽歌,這里就以MusicPlayer(音樂播放器)為案例,一般播放器中都有播放(play),跳過(skip),停止(stop)等功能,是一種比較典型的命令模式
UML圖如下:
1.定義Command(抽象命令類),只有一個execute()用來執行命令
interface Command {void execute(); }2.創建不同指令的ConcreteCommand(具體命令類)
class PlayCommand implements Command {private MusicPlayer musicPlayer;public PlayCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.play();} }class SkipCommand implements Command {private MusicPlayer musicPlayer;public SkipCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.skip();} }class StopCommand implements Command {private MusicPlayer musicPlayer;public StopCommand(MusicPlayer musicPlayer) {this.musicPlayer = musicPlayer;}@Overridepublic void execute() {musicPlayer.stop();} }3.MusicInvoker(調用者),接收客戶端發送過來的指令
class MusicInvoker {private Command playCommand;private Command skipCommand;private Command stopCommand;public void setPlayCommand(Command playCommand) {this.playCommand = playCommand;}public void setSkipCommand(Command skipCommand) {this.skipCommand = skipCommand;}public void setStopCommand(Command stopCommand) {this.stopCommand = stopCommand;}public void play() {playCommand.execute();}public void skip() {skipCommand.execute();}public void stop() {stopCommand.execute();} }4.MusicPlayer(接收者),執行接收到的指令
class MusicPlayer {public void play() {System.out.println("播放...");}public void skip() {System.out.println("跳過...");}public void stop() {System.out.println("停止...");} }5.測試類MusicPlayerClient
public class MusicPlayerClient {public static void main(String[] args) {// 創建 Receiver(接收者)MusicPlayer musicPlayer = new MusicPlayer();// Command(抽象命令類)Command playCommand = new PlayCommand(musicPlayer);Command skipCommand = new SkipCommand(musicPlayer);Command stopCommand = new StopCommand(musicPlayer);// 創建 Invoker(調用者)MusicInvoker invoker = new MusicInvoker();invoker.setPlayCommand(playCommand);invoker.setSkipCommand(skipCommand);invoker.setStopCommand(stopCommand);// 測試invoker.play();invoker.skip();invoker.stop();invoker.play();invoker.stop();} }6.運行結果
宏命令
宏命令: 又稱為組合命令,組合多個命令,它是命令模式和組合模式聯用的產物;
假設MusicPlayer(音樂播放器)有一個記錄功能,可以把每一個命令記錄下來,在需要的時候又可以將歷史記錄的命令在執行一遍,這就是所謂的宏命令集功能。
UML圖如下:
1.定義MacroCommand(宏命令類),繼承基礎Command(命令類)
interface MacroCommand extends Command {void add(Command command);void remove(Command command); }2.創建MacroMusicCommand實現MacroCommand
class MacroMusicCommand implements MacroCommand {private static final List<Command> COMMANDS = new ArrayList<>();@Overridepublic void execute() {System.out.println("==========回放開始==========");COMMANDS.forEach(Command::execute);System.out.println("==========回放結束==========");}@Overridepublic void add(Command command) {COMMANDS.add(command);}@Overridepublic void remove(Command command) {COMMANDS.remove(command);} }3.測試類
public class MusicPlayerClient {public static void main(String[] args) {// 創建 Receiver(接收者)MusicPlayer musicPlayer = new MusicPlayer();// Command(抽象命令類)Command playCommand = new PlayCommand(musicPlayer);Command skipCommand = new SkipCommand(musicPlayer);Command stopCommand = new StopCommand(musicPlayer);// 創建 Invoker(調用者)MacroCommand macroCommand = new MacroMusicCommand();macroCommand.add(playCommand);macroCommand.add(skipCommand);macroCommand.add(stopCommand);// 測試macroCommand.execute();} }4.運行結果
JDK中應用
我們平時使用的java.lang.Runnable就是命令模式的經典應用
// 命令類 與 具體命令實現類 Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("關注 battcn 公眾號即可免費領取視頻");} }; // Invoker(調用者) 接收命令 Thread thread = new Thread(runnable); // 調用 start 命令 thread.start(); // JDK8 簡化寫法 new Thread(()->System.out.println("關注 battcn 公眾號即可免費領取視頻")).start();總結
優點
- 將行為調用者和各種行為分隔開,降低程序的耦合,便于程序擴展;
- 將行為的具體實現封裝起來,客戶端無需關心行為的具體實現;
- 為多種行為提供統一的調用入口,便于程序對行為的管理和控制;
缺點
- 使用命令模式,不論命令簡單還是復雜,都需要寫一個命令類來封裝,濫用命令模式會導致系統出現過多的具體命令類;
適用場景
- 希望將行為請求者和行為實現者解耦,不直接打交道;
- 希望分離掉行為請求者一部分的責任,行為請求者只需要將命令發給調用者,不再主動的去讓行為實現者產生行為,符合單一職責原則;
- 希望可以控制執行的命令列表,方便記錄,撤銷/重做以及事務等功能;
- 希望可以將請求組合使用,即支持宏命令;
說點什么
全文代碼:https://gitee.com/battcn/design-pattern/tree/master/Chapter12/battcn-command
- 個人QQ:1837307557
- battcn開源群(適合新手):391619659
微信公眾號:battcn(歡迎調戲)
福利
關注公眾號:battcn,回復springboot即可獲得 <Spring Boot從入門到實戰 基礎實戰系列教程全集> 與 <2017最新spring boot 外賣實戰微信公眾平臺視頻教程>
總結
以上是生活随笔為你收集整理的一起学设计模式 - 命令模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CCNP路由实验---12、配置分发列表
- 下一篇: Adobe Flash Player 1