將「請求」封裝成對象,以便使用不一樣的請求、隊列或者日誌來參數化其餘對象。命令模式也支持可撤銷的操做。 java
調用者與實現者一般是一種緊耦合的關係,但某些場合,好比須要對行爲進行記錄、撤銷或重作、事務等處理時,這種沒法抵禦變化的緊耦合的設計就不太合適。 我一般這麼理解命令模式,某些業務場景,一族對象會有一組命令,以命令的角度爲主定義命令對象(有執行和撤回兩種操做),而後把執行的過程委託給對象。this
什麼是一族對象?舉個例子,就是奔馳汽車、寶馬汽車、奧迪汽車等。spa
什麼是一組命令?舉個例子,就是遠程控制汽車時的開門命令、開空調命令、開天窗命令等。線程
這種狀況就可使用命令模式。使用命令模式有下降耦合、可擴展、可讀性高、使用方便(可撤回)等等的好處。設計
具體咱們來看一下,如何用Java代碼實現命令模式。日誌
仍是以上面的需求爲例子,使用命令模式對上面的業務進行實現,下面是類圖和代碼:code
代碼以下:對象
// 車輛抽象類 public abstract class Vehicle { abstract void openDoor(); abstract void openWindow(); } public class Audi extends Vehicle { void openDoor() { System.out.println("奧迪:開門。"); } void openWindow() { System.out.println("奧迪:開窗。"); } } public class Benz extends Vehicle { void openDoor() { System.out.println("奔馳:開門。"); } void openWindow() { System.out.println("奔馳:開窗。"); } } // 命令模式接口 public interface Command { void execute(); } // 開門命令 public class OpenDoorCommand implements Command { private Vehicle vehicle; public OpenDoorCommand(Vehicle vehicle) { this.vehicle = vehicle; } public void execute() { vehicle.openDoor(); } } // 開窗命令 public class OpenWindowCommand implements Command { private Vehicle vehicle; public OpenWindowCommand(Vehicle vehicle) { this.vehicle = vehicle; } public void execute() { vehicle.openWindow(); } } public class Client { public static void main(String[] args) { // 建立開門命令 Command openDoorCommand = new OpenDoorCommand(new Benz()); // 建立開窗命令 Command openWindowCommand = new OpenWindowCommand(new Audi()); // 執行2個命令 openDoorCommand.execute(); openWindowCommand.execute(); } } //輸出: //奔馳:開門。 //奧迪:開窗。
使用命令的模式的好處以下:blog
功能足夠簡單。若是功能自己比較簡單,則不建議引入命令模式,它會帶來更多的複雜性,以及更高的開發成本。接口
命令的意義不清晰或常常變化時,則不太適合使用命令模式。
通常來講,儘可能設計傻瓜式命令,它只懂得調用一個接收者的一個行爲(單一職責)。
如何實現撤銷命令,是一直值得討論的問題,面相擴展性來講,能夠遵循一個設計方式:
不要只是記錄最後一個命令,而使用一個堆棧(後進先出)記錄操做過的每個命令。而後,無論何時執行撤銷,你均可以從堆棧中取出最上層的命令,而後執行undo()方法來撤銷它。
最後說一些其餘的,命令模式還能夠有更多的用途,好比使用在隊列請求和日誌請求。
想象一下,有一個工做隊列(先進先出),你在某一端添加命令,而後另外一端則是線程,線程從隊列中取出一個命令,而後調用它的execute()方法,等待這個調用完成,而後丟棄該命令,執行下一個……
在想象一下,某些應用須要咱們將全部的動做都記錄在日誌中,並能在系統死機後,從新調用這些動做恢復到以前的狀態。咱們能夠在執行命令的時候,將歷史記錄存儲在磁盤中。一旦系統死機重啓後,咱們就能夠將命令對象讀取出來從新執行execute()方法。
以上就是我對命令模式的一些理解,有不足之處請你們指出,謝謝。