封裝調用:將方法調用給封裝起來。
此次講的是命令模式,他的做用就是方法給封裝起來,有須要的時候就調用,調用者並不須要關心它是如何實現的。 編程
咱們來看一張流程圖
注:
一、訂單封裝了準備餐點的請求,
二、女服務員的工做是接受訂單,而後調用訂單的orderUp方法,女服務員並不關心訂單內容是什麼,她只需調用orderUp方法
三、廚師就是一個對象,他是真正知道餐點的具體內容的人,一旦女服務員調用orderUp方法,廚師就接手,實現餐點的具體方法,這裏廚師和女服務員是解耦的,訂單封裝了餐點的細節,她只要調用每一個訂單的方法便可,而廚師看了訂單就知道該作些什麼餐點。設計模式
好的,我從新繪製了一張圖反映命令模式以下圖,流程與上圖相同。
數組
OK,咱們基本瞭解了命令模式的流程怎樣
下面寫一個模擬遙控器打開電燈和門這麼個動做的Demo例子app
一、寫電燈和門的類ide
電燈測試
package Entity; public class Light { public Light() { } public void on() { System.out.println("燈亮了"); } public void off() { System.out.println("燈滅了"); } }
門this
package Entity; public class Door { public Door() { } public void OpenDoor() { System.out.println("門開了"); } public void OffDoor() { System.out.println("門關了"); } public void StopDoor(){ System.out.println("門中止了"); } public void DoorLightOn(){ System.out.println("門裏的燈亮了"); } }
二、建立命令接口spa
package Interface; /** * 命令接口 * * @author Joy * */ public interface Command { // 命令執行方法 public void execute(); }
三、實現一個打開電燈的命令設計
package Implements; import Entity.Light; import Interface.Command; public class LightOnCommand implements Command { Light light; // 構造器中傳入某個電燈類型 // 以便讓這個命令控制,而後記錄在light實例變量中, // 當調用execute時,light會根據類型不一樣執行不一樣燈亮方法 public LightOnCommand(Light light) { this.light = light; } // 執行燈亮方法 @Override public void execute() { light.on(); } }
門的實現方法日誌
package Implements; import Entity.Door; import Interface.Command; public class DoorOpenCommand implements Command { Door door; public DoorOpenCommand(Door door) { this.door = door; } @Override public void execute() { door.OpenDoor(); } }
四、調用命令對象(遙控器)
package Control; import Interface.Command; /** * 簡單遙控器 *至關於調用者 * @author Joy * */ public class SimpleRemoteControl { // 命令對象類型,至關於插槽控制着一個裝置 Command slot; public SimpleRemoteControl() { } // 這個方法用來設置插槽控制的命令 // 若是客戶須要改變遙控器按鈕的行爲,能夠屢次調用此方法 public void setCommand(Command command) { slot = command; } // 執行方法 public void buttonWasPressed() { slot.execute(); } }
五、測試類(使用遙控器)
package TestMain; import Control.SimpleRemoteControl; import Entity.Door; import Entity.Light; import Implements.DoorOpenCommand; import Implements.LightOnCommand; public class LightTestMain { public static void main(String[] args) { // 遙控器至關於命令的調用者,會傳入一個命令對象,能夠用來發送請求 SimpleRemoteControl remote = new SimpleRemoteControl(); // 建立一個電燈對象,此對象也就是請求中的接收者 Light light = new Light(); Door door = new Door(); // 建立打開電燈動做的類,並傳入接收者(light) LightOnCommand lightOn = new LightOnCommand(light); DoorOpenCommand doorOpen = new DoorOpenCommand(door); // 命令傳給調用者(遙控器) remote.setCommand(lightOn); // 模擬按下按鈕 remote.buttonWasPressed(); remote.setCommand(doorOpen); remote.buttonWasPressed(); } }
效果圖
這就是個基本命令模式的使用算是牛刀小試了一下,
命令模式定義:將「請求」封裝成對象,以便使用不一樣的請求、隊列或者日誌 來參數化其餘對象,命令模式也支持可撤銷的操做。
下面是這模式的類圖
接下來繼續模擬一個遙控器,只不過此次需求變得複雜了起來。
示例圖以下,
每一個遙控器的插槽都對應一個命令嗎,這樣遙控器就變爲了「調用者」,當按下按鈕,對應的命令對象的execute方法就會被調用,結果就是接收者(例如:電燈,天花板電扇,音響)的動做被調用。
代碼開始
一、實體類
電燈
package Entity; public class Light { //所處位置 String location; public Light(String location) { this.location = location; } public void on(){ System.out.println(location+"燈亮了"); } public void off(){ System.out.println(location+"燈關了"); } }
音響
package Entity; /** * 音響類 * * @author Joy * */ public class Stereo { //location 一個地點變量 String location; public Stereo(String location) { this.location = location; } public void on(){ System.out.println(location+"音響啓動"); } public void off(){ System.out.println(location+"音響關閉"); } public void setDVD(){ System.out.println(location+"音響放一張DVD並播放"); } public void setCD(){ System.out.println(location+"音響放一張CD並播放"); } public void setRadio(){ System.out.println(location+"音響以收音機無線電形式播放"); } public void setVolume(int volume) { System.out.println(location + " 音響音量設置爲 " + volume); } }
電視
package Entity; public class TV { String location; int channel;//電視頻道 public TV(String location) { this.location = location; } public void TVOn(){ System.out.println(location+"電視自動打開了"); } public void TVOff(){ System.out.println(location+"電視自動關閉了"); } //電視調頻道 public void setTVChannel(int channel){ this.channel=channel; System.out.println(location+"電視自動調到"+channel+"頻道"); } }
二、建立命令接口對象
package Interface; public interface Command { //執行 public void execute(); //撤銷 public void undo(); }
三、實現遙控器類(調用者)
package Control; import Implements.NoCommand; import Interface.Command; /** * 實現遙控器 * * @author Joy */ public class RemoteControl { // 此時遙控器要處理7個開關控制,使用數組 Command[] onCommands = new Command[7]; Command[] offCommands = new Command[7]; // 撤銷固然要先知道以前的命令 // 撤銷變量,用來追蹤最後被調用的命令 Command undoCommand; // 初始化遙控器類,一開始都是無操做noCommand是一個無操做對象 // 在測試輸出時,沒有被明確指明命令的插槽,其命令默認爲noCommand對象 public RemoteControl() { Command noCommand = new NoCommand(); for (int i = 0; i < onCommands.length; i++) { onCommands[i] = noCommand; offCommands[i] = noCommand; } undoCommand = noCommand; } /** * * @param slot * :插槽的位置(相似索引值) * @param onCommand * :開的命令 * @param offCommand * :關的命令 這些命令被記錄在開關數組對應的插槽位置上,以便使用 */ public void setCommand(int slot, Command onCommand, Command offCommand) { onCommands[slot] = onCommand; offCommands[slot] = offCommand; } /** * 開關按鈕是對應的插槽位置負責調用對應的方法 * 遙控器上面開關按鈕的不一樣位置就能夠控制不一樣類型的燈 * undoCommand:當按下遙控器按鈕時,咱們取得這個命令,並記錄在undoCommand裏 * @param slot */ public void onButtonWasPushed(int slot) { onCommands[slot].execute(); undoCommand=onCommands[slot]; } public void offButtonWasPushed(int slot) { offCommands[slot].execute(); undoCommand=offCommands[slot]; } //添加一個撤銷按鈕 public void undoButtonWasPushed(){ //撤銷 undoCommand.undo(); } // 打印每一個插槽和它對應的命令 @Override public String toString() { StringBuffer sbf = new StringBuffer(); sbf.append("\n======================遙控器======================\n"); for (int i = 0; i < onCommands.length; i++) { sbf.append("[插槽" + i + "]" + onCommands[i].getClass().getName() + "\t" + offCommands[i].getClass().getName() + "\n"); } return sbf.toString(); } }
四、實現各個命令(7個)
package Implements; import Entity.Light; import Interface.Command; public class LightOffCommand implements Command { //具體對象變量 Light light; public LightOffCommand(Light light) { this.light = light; } @Override public void execute() { light.off(); } @Override public void undo() { light.on(); } }
package Implements; import Entity.Light; import Interface.Command; public class LightOnCommand implements Command { // 具體對象變量 Light light; public LightOnCommand(Light light) { this.light = light; } // 執行打開電燈方法 @Override public void execute() { light.on(); } // 撤銷操做,關閉電燈 @Override public void undo() { light.off(); } }
package Implements; import Interface.Command; public class NoCommand implements Command { // 這是個無操做類,插槽內的類沒有實例化是就走這個對象 @Override public void execute() { } @Override public void undo() { // TODO 自動生成的方法存根 } }
package Implements; import Entity.Stereo; import Interface.Command; public class StereoOffCommand implements Command { // 具體對象變量 Stereo stereo; public StereoOffCommand(Stereo stereo) { this.stereo = stereo; } public void execute() { stereo.off(); } @Override public void undo() { stereo.on(); } }
package Implements; import Entity.Stereo; import Interface.Command; /** * 音響的 * * @author Joy * */ public class StereoOnWithCDCommand implements Command { // 具體對象變量 Stereo stereo; public StereoOnWithCDCommand(Stereo stereo) { this.stereo = stereo; } // 具體實現方法(方法再去調用實現方法) public void execute() { stereo.on(); stereo.setCD(); stereo.setVolume(11); } @Override public void undo() { stereo.off(); } }
package Implements; import Entity.TV; import Interface.Command; public class TVOffCommand implements Command { TV tv; public TVOffCommand(TV tv) { this.tv = tv; } @Override public void execute() { tv.TVOff(); } @Override public void undo() { tv.TVOn(); } }
package Implements; import Entity.TV; import Interface.Command; public class TVOnCommand implements Command { TV tv; public TVOnCommand(TV tv) { this.tv = tv; } @Override public void execute() { tv.TVOn(); tv.setTVChannel(15); } @Override public void undo() { tv.TVOff(); } }
五、測試類
package TestMain; import Control.RemoteControl; import Entity.Light; import Entity.Stereo; import Entity.TV; import Implements.LightOffCommand; import Implements.LightOnCommand; import Implements.StereoOffCommand; import Implements.StereoOnWithCDCommand; import Implements.TVOffCommand; import Implements.TVOnCommand; public class TestMain { public static void main(String[] args) { // 實例化遙控器 RemoteControl remoteControl = new RemoteControl(); // 實例化須要控制對象,並傳入房子位置 Stereo stereo = new Stereo("客廳"); Light light = new Light("客廳"); TV tv = new TV("臥室"); // 調用設備開關方法 StereoOnWithCDCommand stereoOnWichCD = new StereoOnWithCDCommand(stereo); StereoOffCommand stereoOffWithCD = new StereoOffCommand(stereo); LightOnCommand lightOn = new LightOnCommand(light); LightOffCommand lightOff = new LightOffCommand(light); TVOnCommand tvOn = new TVOnCommand(tv); TVOffCommand tvOff = new TVOffCommand(tv); // 設置插槽位置(遙控器的哪一個按鈕對應哪一個設備開關) remoteControl.setCommand(0, lightOn, lightOff); remoteControl.setCommand(3, stereoOnWichCD, stereoOffWithCD); remoteControl.setCommand(5, tvOn, tvOff); // 輸出插槽位置 System.out.println(remoteControl); // 按下開關 remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); remoteControl.onButtonWasPushed(3); remoteControl.offButtonWasPushed(3); remoteControl.onButtonWasPushed(5); remoteControl.offButtonWasPushed(5); } }
效果圖
+1~~~~
在這個實例當中我特地預留了撤銷的功能,讓咱們看看加上撤銷功能(undo)的遙控器是怎麼運行的把。
新建一個undoCommandTest類
package TestMain; import Control.RemoteControl; import Entity.Light; import Implements.LightOffCommand; import Implements.LightOnCommand; public class undoCommandTest { public static void main(String[] args) { // 實例化遙控器 RemoteControl remoteControl = new RemoteControl(); // 實例化須要控制對象,並傳入房子位置 Light light = new Light("客廳"); // 調用設備開關方法 LightOnCommand lightOn = new LightOnCommand(light); LightOffCommand lightOff = new LightOffCommand(light); // 設置插槽位置(遙控器的哪一個按鈕對應哪一個設備開關) remoteControl.setCommand(0, lightOn, lightOff); // 按下開關 remoteControl.onButtonWasPushed(0); remoteControl.offButtonWasPushed(0); // 輸出插槽位置 System.out.println(remoteControl); // 撤銷 System.out.println("按下撤銷按鈕"); remoteControl.undoButtonWasPushed(); System.out.println(""); remoteControl.offButtonWasPushed(0); remoteControl.onButtonWasPushed(0); System.out.println(remoteControl); System.out.println("按下撤銷按鈕"); remoteControl.undoButtonWasPushed(); } }
效果圖
看來撤銷的功能也OK,我腦中甚至浮現出在JavaWeb裏這個撤銷的效果了,23333。
感謝你看到這裏,命令模式的上部分到這裏就結束了,本人文筆隨便,如有不足或錯誤之處望給予指點,90度彎腰~~~很快我會發布命令模式下的內容,生命不息,編程不止!
參考書籍:《Head First 設計模式》