设计模式 命令模式 之 管理智能家电
繼續設計模式哈,今天帶來命令模式,二話不說,先看定義:
定義:將“請求”封裝成對象,以便使用不同的請求、隊列或者日志來參數化其他對象。命令模式也支持可撤銷的操作。
這尼瑪定義,看得人蛋疼,看不明白要淡定,我稍微簡化一下:將請求封裝成對象,將動作請求者和動作執行者解耦。好了,直接用例子來說明。
需求:最近智能家電很火熱啊,未來尼瑪估計冰箱都會用支付寶自動買東西了,,,,假設現在有電視、電腦、電燈等家電,現在需要你做個遙控器控制所有家電的開關,要求做到每個按鈕對應的功能供用戶個性化,對于新買入家電要有非常強的擴展性。
這個需求一看,尼瑪要是沒有什么個性化、擴展性還好說啊,直接針對每個遙控器的按鈕onClick,然后在里面把代碼寫死就搞定了,但是個性化怎么整,還要有擴展性。。。
好了,下面命令模式出場,命令模式的核心就是把命令封裝成類,對于命令執行者不需要知道現在執行的具體是什么命令。
1、首先看下我們擁有的家電的API:
package com.zhy.pattern.command; /*** 門* @author zhy**/ public class Door {public void open(){System.out.println("打開門");}public void close(){System.out.println("關閉門");}}package com.zhy.pattern.command;/*** 電燈* @author zhy**/ public class Light {public void on(){System.out.println("打開電燈");}public void off(){System.out.println("關閉電燈");} }
package com.zhy.pattern.command; /*** 電腦* @author zhy**/ public class Computer {public void on(){System.out.println("打開電腦");}public void off(){System.out.println("關閉電腦");} }
看來我們有電燈、電腦、和門,并且開關的接口的設計好了。接下來看如何把命令封裝成類: package com.zhy.pattern.command;public interface Command {public void execute(); }
package com.zhy.pattern.command;/*** 關閉電燈的命令* @author zhy**/ public class LightOffCommond implements Command {private Light light ; public LightOffCommond(Light light){this.light = light;}@Overridepublic void execute(){light.off();}}
package com.zhy.pattern.command;/*** 打開電燈的命令* @author zhy**/ public class LightOnCommond implements Command {private Light light ; public LightOnCommond(Light light){this.light = light;}@Overridepublic void execute(){light.on();}}
package com.zhy.pattern.command;/*** 開電腦的命令* @author zhy**/ public class ComputerOnCommond implements Command {private Computer computer ; public ComputerOnCommond( Computer computer){this.computer = computer;}@Overridepublic void execute(){computer.on();}}
package com.zhy.pattern.command;/*** 關電腦的命令* @author zhy**/ public class ComputerOffCommond implements Command {private Computer computer ; public ComputerOffCommond( Computer computer){this.computer = computer;}@Overridepublic void execute(){computer.off();}}
好了,不貼那么多了,既然有很多命令,按照設計原則,我們肯定有個超類型的Command,然后各個子類,看我們把每個命令(請求)都封裝成類了。接下來看我們的遙控器。 package com.zhy.pattern.command;/*** 控制器面板,一共有9個按鈕* * @author zhy* */ public class ControlPanel {private static final int CONTROL_SIZE = 9;private Command[] commands;public ControlPanel(){commands = new Command[CONTROL_SIZE];/*** 初始化所有按鈕指向空對象*/for (int i = 0; i < CONTROL_SIZE; i++){commands[i] = new NoCommand();}}/*** 設置每個按鈕對應的命令* @param index* @param command*/public void setCommand(int index, Command command){commands[index] = command;}/*** 模擬點擊按鈕* @param index*/public void keyPressed(int index){commands[index].execute();}}
package com.zhy.pattern.command;/*** @author zhy**/ public class NoCommand implements Command {@Overridepublic void execute(){}}
注意看到我們的遙控器有9個按鈕,提供了設置每個按鈕的功能和點擊的方法,還有注意到我們使用了一個NoCommand對象,叫做空對象,這個對象的好處就是,我們不用執行前都判斷個if(!=null),并且提供了一致的操作。
最后測試一下代碼:
package com.zhy.pattern.command;public class Test {public static void main(String[] args){/*** 三個家電*/Light light = new Light();Door door = new Door();Computer computer = new Computer();/*** 一個控制器,假設是我們的app主界面*/ControlPanel controlPanel = new ControlPanel();// 為每個按鈕設置功能controlPanel.setCommand(0, new LightOnCommond(light));controlPanel.setCommand(1, new LightOffCommond(light));controlPanel.setCommand(2, new ComputerOnCommond(computer));controlPanel.setCommand(3, new ComputerOffCommond(computer));controlPanel.setCommand(4, new DoorOnCommond(door));controlPanel.setCommand(5, new DoorOffCommond(door));// 模擬點擊controlPanel.keyPressed(0);controlPanel.keyPressed(2);controlPanel.keyPressed(3);controlPanel.keyPressed(4);controlPanel.keyPressed(5);controlPanel.keyPressed(8);// 這個沒有指定,但是不會出任何問題,我們的NoCommand的功勞} }輸出結果:
可以看到任意按鈕可以隨意配置任何命令,再也不需要尼瑪的變一下需求改代碼了,隨便用戶怎么個性化了。其實想白了,這里的設置我們還可以配置到一個配置文件中,完全的解耦有木有。
好了,用戶對于這個按鈕可能還不是太滿意,用戶希望夜深人靜的時候,能夠提供個按鈕直接關門、關燈、開電腦,,,,大家懂的,,,我們稍微修改下代碼,滿足他
定義一個命令,用戶干一些列的事,可配置,且與原來的命令保持接口一致:
package com.zhy.pattern.command;/*** 定義一個命令,可以干一系列的事情* * @author zhy* */ public class QuickCommand implements Command {private Command[] commands;public QuickCommand(Command[] commands){this.commands = commands;}@Overridepublic void execute(){for (int i = 0; i < commands.length; i++){commands[i].execute();}}}好了,已經滿足屌絲的需求了。我們測試看看。 // 定義一鍵搞定模式QuickCommand quickCommand = new QuickCommand(new Command[] { new DoorOffCommond(door),new LightOffCommond(light), new ComputerOnCommond(computer) });System.out.println("****點擊一鍵搞定按鈕****");controlPanel.setCommand(8, quickCommand);controlPanel.keyPressed(8);
是不是很完美。
最后,繼續來談談命令模式,命令模式就是把命令封裝成對象,然后將動作請求者與動作執行者完全解耦,上例中遙控器的按鈕和電器一毛錢關系都沒吧。
還記得定義中提到了隊列,命令模式如何用于隊列呢,比如飯店有很多個點菜的地方,有一個做菜的地方,把點菜看作命令,做菜看作命令執行者,不斷有人點菜就相當于把菜加入隊列,對于做菜的只管從隊列里面取,取一個做一個。
定義中還提到了日志,日志一般用于記錄用戶行為,或者在異常時恢復時用的,比如每個命令現在包含兩個方法,一個執行execute,一個undo(上例中為了方便大家理解,沒有寫undo),我們可以把用戶所有命令調用保存到日志中,比如用戶操作不當了,電器異常了,只需要把日志中所有的命令拿出來執行一遍undo就完全恢復了,是吧,就是這么個意思。
好了,各位留個言、點個贊算是對我的支持,多謝大家~
版權聲明:本文為博主原創文章,未經博主允許不得轉載。
轉載于:https://www.cnblogs.com/dingxiaoyue/p/4924964.html
總結
以上是生活随笔為你收集整理的设计模式 命令模式 之 管理智能家电的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uifont 字体详解
- 下一篇: 摄像头光圈大小对景深的影响