14.java設計模式之命令模式
阿新 • • 發佈:2020-11-25
#### 基本需求:
* 一套智慧家電,有照明燈、風扇、冰箱、洗衣機,我們只要在手機上安裝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方法中有如下程式碼
>