本文首發於cdream的我的博客,點擊得到更好的閱讀體驗!html
歡迎轉載,轉載請註明出處。java
本文主要對命令模式進行概述講解,並使用使用遙控器與燈來說述命令模式中調用者與接收者的關係。git
<!--more-->github
命令模式(英語:Command pattern)是一種設計模式,它嘗試以對象來表明實際行動。命令對象能夠把行動(action) 及其參數封裝起來,因而這些行動能夠被重複使用、撤銷、撤銷後重作。設計模式
這個是概念是來自維基百科,我以爲最容易理解,就是把命令封裝成對象,使命令能夠重複調用、撤銷,下降了調用者和接受者的耦合,同時容易擴展出新的命令。多線程
<div class="note"><strong>其餘描述</strong>:<br>1.將「請求」封裝成對象,以便使不一樣的請求、隊列或日誌來參數化其餘對象,命令模式也支持可撤銷操做。(Head First 設計模式)<br>2.命令模式把一個請求或者操做封裝到一個對象中。命令模式容許系統使用不一樣的請求把客戶端參數化,對請求排隊或者記錄請求日誌,能夠提供命令的撤銷和恢復功能。(Java與模式)</div>ide
你們作適當參考,不理解能夠先看看下面的源碼!this
如圖,這是命令模式的結構:spa
以用遙控器開燈爲例(Head First 設計模式例子)線程
Invoker:命令調用者,負責調用命令對象的請求——遙控器
Command:聲明瞭一個具體命令類實現的接口——命令的接口
ConcreteCommand:具體命令,實現了Invoker和Receiver之間的解耦,一般持有接收者對象的飲用——開燈按鈕執行的命令
Receiver:命令接收者,真正接收命令並執行動做的對象——燈
Client:客戶端,創造具體的命令,並肯定接收者
Receiver——二檔亮度的燈
// 二檔調節的燈,在這裏做爲接收者 public class Light { public static final String HIGH = "賊亮"; public static final String MEDIUM = "有點亮"; public static final String LOW = "快滅火了"; public static final String OFF = "真的滅火了~"; private String luminance; public Light() { this.luminance = OFF; } public void off() { System.out.println("燈關閉了"); this.luminance = OFF; } public void high() { System.out.println("賊亮"); this.luminance = HIGH; } public void medium() { System.out.println("挺亮地!"); this.luminance = MEDIUM; } public void low() { System.out.println("快滅火了"); this.luminance = LOW; } public String getLuminance(){ return this.luminance; } }
Command——作個命令接口,帶撤銷功能
public interface Command { void excute(); void undo(); }
LightHighCommand——高光命令
public class LightHighCommand implements Command { private Light light; private String preLuminance; @Override public void excute() { // 備份上一個命令,撤銷使用 preLuminance = light.getLuminance(); light.high(); } @Override public void undo() { if (Light.HIGH.equals(preLuminance)){ light.high(); }else if(Light.MEDIUM.equals(preLuminance) ){ light.medium(); }else if (Light.LOW.equals(preLuminance)){ light.low(); }else if (Light.OFF.equals(preLuminance)){ light.off(); } } public LightHighCommand(Light light) { this.light = light; } // 智能遙控器按鍵功能能夠控制多個燈 // 若是控制令一個接收者,能夠傳入,不用新建命令 public void setLight(Light light) { this.light = light; } }
LightOffCommand——關燈命令
public class LightOffCommand implements Command { private Light light; private String preLuminance; public LightOffCommand(Light light) { this.light = light; } @Override public void excute() { preLuminance = light.getLuminance(); light.off(); } @Override public void undo() { if (Light.HIGH.equals(preLuminance)){ light.high(); }else if(Light.MEDIUM.equals(preLuminance) ){ light.medium(); }else if (Light.LOW.equals(preLuminance)){ light.low(); }else if (Light.OFF.equals(preLuminance)){ light.off(); } } public void setLight(Light light) { this.light = light; } }
Invoker——遙控器
public class RemoteControl { private Command off; private Command high; private Command medium; private Command low; private Command preCommand; public void setOff(Command off) { this.off = off; } public void setHigh(Command high) { this.high = high; } public void setMedium(Command medium) { this.medium = medium; } public void setLow(Command low) { this.low = low; } public void lightOff() { off.excute(); preCommand = off; } public void lightHigh() { high.excute(); preCommand = high; } public void lightMedium() { medium.excute(); preCommand = medium; } public void lightLow() { low.excute(); preCommand = low; } public void undo() { if (preCommand == null) { System.out.println("沒法撤銷"); } else { preCommand.undo(); } } }
Client——客戶端
public class Client { public static void main(String[] args) { // 建立接收者 Light light = new Light(); // 建立命令 Command lightHighCommand = new LightHighCommand(light); Command lightOffCommand = new LightOffCommand(light); // 建立調用者 RemoteControl remoteControl = new RemoteControl(); remoteControl.setHigh(lightHighCommand); remoteControl.setOff(lightOffCommand); // 調用 remoteControl.lightHigh(); remoteControl.lightOff(); remoteControl.undo(); } } ————————>結果 賊亮 燈關閉了 賊亮
以上就是一個帶撤回功能的命令模式,其中:
若是想實現多步撤回,能夠考慮把調用者中的preCommand換成stack;
若是想實現組合命令,能夠從新建立一個宏命令,以下
public class MacroCommand implements Command { private Command[] commands; public MacroCommand(Command[] commands) { this.commands = commands; } @Override public void excute() { for (Command command : commands) { command.excute(); } } @Override public void undo() { for (Command command : commands) { command.undo(); } } }
你能夠用這個命令實現任何形式的命令組合,甚至若是你以爲你的遙控器能夠控制空調,控制電源,控制電飯鍋,你甚至能夠把這些命令組合進來~
解耦合:將命令調用者和命令執行者經過命令進行解耦,命令調用者不關心由誰來執行命令,只要命令執行就能夠
更動態的控制:請求被封裝成對象後,能夠輕易的參數化、隊列化、日誌化,使系統更加靈活。
更容易的命令組合:有了宏命令後,能夠任意的對命令進行組合
更好擴展性:能夠輕易的添加新的命令,並不會影響到其餘的命令
本文對命令模式做了簡單的介紹,命令模式只要明白調用者如何經過命令與接收者交互,就比較好理解。在實際應用中,命令模式能夠用在並行處理、事務行爲、線程池等地方。例如傳統的線程池就有addTask()方法將命令加入到等待被執行的隊列中,容許多線程執行實現java.lang.Runnable
的命令,儘管線程池自己對具體的任務毫無認知。