1. 程式人生 > >14.java設計模式之命令模式

14.java設計模式之命令模式

#### 基本需求: * 一套智慧家電,有照明燈、風扇、冰箱、洗衣機,我們只要在手機上安裝app就可以控制對這些家電工作 * 這些智慧家電來自不同的廠家,我們不想針對每一種家電都安裝一個App分別控制,我們希望只要一個app就可以控制全部智慧家電 * 要實現一個app控制所有智慧家電的需要,則每個智慧家電廠家都要提供一個統一的介面給app呼叫,這時就可以考慮使用命令模式 * 命令模式可將“動作的請求者”從“動作的執行者”物件中解耦出來 * 也就是說,每一種家電都有開和關兩種操作,一組命令 #### 基本介紹: * 命令模式(Command):在軟體設計中,我們經常需要向某些物件傳送請求,並不知道請求的接收者是誰,不知道被請求的操作是哪個,我們只需在程式執行時指定具體的請求接收者即可,此時,可以使用命令模式來進行設計 * 命令模式使得請求傳送者與請求接收者消除彼此之間的耦合,讓物件之間的呼叫關係更加靈活,實現解耦 * 命令模式中,會將一個請求封裝為一個物件,以便使用不同引數來表示不同的請求(即命令),同時命令模式也必須支援可撤銷的操作 * 將軍釋出命令,士兵去執行。其中有幾個角色:將軍(命令釋出者)、士兵(命令的具體執行者)、命令(連線將軍和士兵) * Invoker 是呼叫者(將軍),Receiver 是被呼叫者(士兵),MyCommand 是命令,實現了 Command 介面,持有接收物件 * UML類圖(原理) * ![](https://img2020.cnblogs.com/blog/2093590/202011/2093590-20201125152405679-829356705.png) * 說明 * Invoker:命令呼叫者角色,聚合命令 * Command:是命令介面 * ConcreteCommand:命令的具體實現,聚合命令的接受者 * Receiver:命令的接受者(執行者) * UML類圖(案例) * ![](https://img2020.cnblogs.com/blog/2093590/202011/2093590-20201125152414547-299531942.png) * 程式碼實現 * >```java >public class LightReceiver { > > // 電燈命令的執行者 > > public void on() { > System.out.println("電燈打開了"); > } > > public void off() { > System.out.println("電燈關閉了"); > } > >} >``` > > * >```java >public interface Command { > > // 命令介面 > > // 執行命令和撤銷命令 > void execute(); > > void undo(); > >} > >// 子類一 電燈開命令 >class LightOnCommand implements Command{ > > // 聚合命令的執行者 > private LightReceiver lightReceiver; > > public LightOnCommand(LightReceiver lightReceiver) { > this.lightReceiver = lightReceiver; > } > > @Override > public void execute() { > lightReceiver.on(); > } > > @Override > public void undo() { > lightReceiver.off(); > } > >} > >// 子類二 電燈關命令 >class LightOffCommand implements Command{ > > // 聚合命令的執行者 > private LightReceiver lightReceiver; > > public LightOffCommand(LightReceiver lightReceiver) { > this.lightReceiver = lightReceiver; > } > > @Override > public void execute() { > lightReceiver.off(); > } > > @Override > public void undo() { > lightReceiver.on(); > } > >} > >// 子類三 空命令 對命令介面空實現 >class NoCommand implements Command { > > @Override > public void execute() { > > } > > @Override > public void undo() { > > } > >} >``` * >```java >// 命令呼叫者 >public class RemoteController { > > // 開命令的集合 > private Command[] onCommands; > > // 關命令的集合 > private Command[] offCommands; > > // 記錄上一個執行的命令,便於進行撤銷 > private Command undoCommand; > > public RemoteController() { > // 預設初始化五組開關 一組開關有開和關兩個按鈕,一一對應 > this.onCommands = new Command[5]; > this.offCommands = new Command[5]; > for (int i = 0; i < 5; i++) { > // 將開關命令的值初始化成空命令,防止空指標異常 > this.onCommands[i] = new NoCommand(); > this.offCommands[i] = new NoCommand(); > } > this.undoCommand = new NoCommand(); > } > > // 為某組開關設定命令 > public void setCommand(int index, Command onCommand, Command offCommand) { > if (index >= 0 && index < this.onCommands.length) { > this.onCommands[index] = onCommand; > this.offCommands[index] = offCommand; > } > } > > // 按下開的按鈕,傳送命令執行 > public void onButtonWasPushed(int index) { > if (index >= 0 && index < this.onCommands.length) { > this.onCommands[index].execute(); > // 設定撤銷命令 > this.undoCommand = this.onCommands[index]; > } > } > > // 按下關的按鈕,傳送命令執行 > public void offButtonWasPushed(int index) { > if (index >= 0 && index < this.onCommands.length) { > this.offCommands[index].execute(); > // 設定撤銷命令 > this.undoCommand = this.offCommands[index]; > } > } > > // 按下撤銷按鈕,傳送命令執行,只支援撤銷一次 > public void undoButtonWasPushed() { > this.undoCommand.undo(); > // 重置撤銷命令 > this.undoCommand = new NoCommand(); > } > >} > >``` * >```java >public class Client { > public static void main(String[] args) { > // 建立執行者 > LightReceiver lightReceiver = new LightReceiver(); > // 建立一組電燈開關的命令,並設定執行者 > Command lightOnCommand = new LightOnCommand(lightReceiver); > Command lightOffCommand = new LightOffCommand(lightReceiver); > // 建立命令的傳送者,並設定電燈這一組命令 > RemoteController remoteController = new RemoteController(); > remoteController.setCommand(0, lightOnCommand, lightOffCommand); > // 傳送電燈命令 執行 > System.out.println("------傳送電燈開命令------"); > remoteController.onButtonWasPushed(0); > System.out.println("------傳送電燈關命令------"); > remoteController.offButtonWasPushed(0); > System.out.println("------傳送撤銷命令------"); > remoteController.undoButtonWasPushed(); > > // 使用命令模式對命令進行了封裝,將命令的釋出者和執行者進行了鬆耦合,利於系統的擴充套件 > // 比如再有一組電視的命令,直接建立新的命令類,建立其物件將其設定給命令的釋出者即可,原有的程式碼不需要改變 > } >} >``` #### spring原始碼: * 在spring的JdbcTemplate類中就使用到了命令模式 * >```java >// 在JdbcTemplate的query和execute方法中有如下程式碼 >