這是我參與8月更文挑戰的第7天,活動詳情查看:8月更文挑戰java
歡迎來到今天的學習,今天咱們一塊兒來學習下極其強悍的一種模式----命令者模式。我命令你把這篇文章看完,哈,開個玩笑,多嘮叨幾句,我本月將會對java的設計模式精講,歡迎點擊頭像,關注個人專欄,我會持續更新,加油!程序員
系列文章:shell
設計模式之單例模式設計模式
設計模式之工廠模式bash
設計模式之建造者模式markdown
設計模式之代理模式編輯器
設計模式之訪問者模式ide
...持續更新中post
話很少說,進入正題
我我的認爲該模式在實際場景中運用不少,可能你沒有發現,等我講完以後你就會以爲,你也能夠改造一些東西。咱們能夠理解爲事件類型的通知型模式,好比我經過一個事件去完成什麼操做。那命令就是帶着發佈命令內容去執行。
命令模式的原始定義是:將一個請求封裝爲一個對象,從而讓咱們能夠參數化具備不一樣請求、隊列或日誌請求的其餘對象,並支持可撤銷的操做
注意:從定義中咱們能夠得出,命令模式是爲了將一組操做封裝在對象中而設計的,通俗講,就是爲了將函數方法封裝爲對象以方便傳輸。好比像Java 從 8 之後支持將函數做爲參數傳遞(咱們都應該體驗過stream,lambda表達式等操做。) 這個就是命令模式的核心理解吧。
看下方圖:
從圖中咱們能夠看到五個角色(注意看圖中箭頭指向):
抽象命令類(Command):用於聲明須要作的操做有哪些,當你看到代碼中有Command的時候,能夠知道命令模式有參與了
具體命令類(Command一、2等):實現 Command 接口,其中存儲一個接收者類,並在 execute 調用具體命令時,委託給接收者來執行具體的方法
調用者(Invoker),客戶端經過與調用者交互來操做不一樣的命令對象。
抽象接收者(Receiver),聲明須要執行的命令操做,同時提供給客戶端使用(看圖中箭頭)
具體接收者(Receiver一、2等):實現抽象接收者,用於接收命令並執行真實的代碼邏輯。(有多少命令就有多少執行者)
命令模式的核心關鍵點就在於圍繞着命令來展開,經過抽象不一樣的命令,並封裝到對象,讓不一樣的接收者針對同一個命令都能作出相應的操做。
接下來咱們經過一組場景和代碼來深刻理解下(再看下上方類圖)
對於命令模式的使用場景,一個經典的類比例子就是 Shell 腳本。若是你熟悉 Shell 腳本的話,就會發現一個 Shell 腳本其實就是這裏的 Invoker 調用者,腳本里各式各樣的 ps、cat、sed 等命令就是 Command,而 bash shell 或 z shell 就是做爲接收者來具體實現執行命令的。
固然,命令模式並不只限於操做系統的命令,在實際的業務開發中,多是對應的一組複雜的代碼調用邏輯,好比,觸發數據統計、日誌記錄、鏈路跟蹤等。
咱們設想這樣一種場景,程序員都得在電腦上記錄文檔,咱們有的用有道雲筆記,印象筆記,還有的用mac電腦的備忘錄,這三者都是你打開,而後邊寫邊同步保存,最後你關閉該軟件,這裏面涉及到三種命令:打開,同步保存,關閉
咱們先來建立一個抽象命令類 Command,其中定義一個無返回的方法 execute。
//命令接口
public interface Command {
void execute();
}
複製代碼
再來依次實現打開(Open)、同步保存(syncSave)、關閉(Close)三個操做,每一個操做中都存有一個 Editor(抽象接收者類),在實現方法 execute 時,會調用 Editor 對應的 open、syncSave 和 close 方法。
//具體命令類
public class Open implements Command {
private Editor editor;
public Open(Editor editor) {
this.editor = editor;
}
@Override
public void execute() {
editor.open();
}
}
public class SyncSave implements Command {
private Editor editor;
public Save(Editor editor) {
this.editor = editor;
}
@Override
public void execute() {
editor.save();
}
}
public class Close implements Command{
private Editor editor;
public Close(Editor editor) {
this.editor = editor;
}
@Override
public void execute() {
editor.close();
}
}
複製代碼
而後,咱們須要定義 Editor 的三個操做方法:打開、同步保存和關閉。
public interface Editor {
void open();
void syncSave();
void close();
}
複製代碼
接着咱們再來實現支持 有道雲 的編輯器 YouDaoEditor(具體接收者),分別實現打開、同步保存和關閉三個方法,這裏具體只是打印了三種不一樣的操做。
public class YouDaoEditor implements Editor {
@Override
public void open() {
System.out.println("-> YouDaoEditor 執行 open 操做");
}
@Override
public void syncSave() {
System.out.println("-> YouDaoEditor 執行 syncSave 操做");
}
@Override
public void close() {
System.out.println("-> YouDaoEditor 執行 close 操做");
}
}
複製代碼
一樣,再實現支持 印象筆記 的編輯器 YinXiangEditor,功能和 YouDaoEditor 相同。
public class YinXiangEditor implements Editor {
@Override
public void open() {
System.out.println("-> YinXiangEditor 執行 open 操做");
}
@Override
public void syncSave() {
System.out.println("-> YinXiangEditor 執行 syncSave 操做");
}
@Override
public void close() {
System.out.println("-> YinXiangEditor 執行 close 操做");
}
}
複製代碼
最後,咱們調用一下
//定義一個切入口
public class RunCommond {
private final List<Command> commands;
public RunCommond() {
commands = new ArrayList<>();
}
public void setCommand(Command command) {
commands.add(command);
}
public void run() {
commands.forEach(Command::execute);
}
}
//調用
public class Client {
public static void main(String[] args) {
YouDaoEditor youdaoEditor = new YouDaoEditor();
YinXiangEditor yinxiangEditor = new YinXiangEditor();
Open youdaoOpen = new Open(youdaoEditor);
SyncSave yinxiangSyncSave = new SyncSave(yinxiangEditor);
RunCommond runCommond = new RunCommond();
//暫時寫着兩個命令,其餘同樣。
runCommond.setCommand(youdaoOpen);
runCommond.setCommand(yinxiangSyncSave);
runCommond.run();
}
}
//控制檯輸出
-> YouDaoEditor 執行 open 操做
-> YinXiangEditor 執行 SyncSave 操做
複製代碼
OK,到這裏今天的學習就完成了。
命令模式的使用場景也很是侷限,只能針對命令順序執行的場景,而對於須要多種組合的場景來講,命令模式並非很適合。
命令模式將一個或一組命令封裝爲一個對象,從而可以將函數方法做爲參數進行傳輸,同時還可以解耦客戶端和服務端的直接耦合,適用場景有:作簡單的請求排隊,記錄請求日誌,以及支持可撤銷的操做。
簡單來講,命令模式的本質是對命令進行封裝,將發出命令的責任和執行命令的責任分離開。
另外給你們看段話,我以爲挺好,也能夠放到本文總結,固然也適用於全部的模式,我看過一本書是付政委的《重學設計模式》裏面有這樣一段話,與你們共勉之。
命令模式分爲命令、實現者和調用者。而這三塊內容的拆分也是選擇場景的關鍵因素,通過拆分,可讓邏輯具有單一職責的性質,便於擴展。與if語句相比,這種實現方式下降了耦合性,也方便其餘命令和實現的擴展。但這種設計模式也帶來了一些問題,在各類命令與實現者的組合下,會擴展出不少的實現類,須要管理。學習設計模式必定要勤加練習,哪怕最開始只是模仿實現,屢次練習後再去找一些能夠優化的場景,並逐步運用到本身的開發中,提高本身對代碼的設計感受,讓代碼結構更加清晰,易於擴展。
感謝你的閱讀,若是你感受學到了東西,麻煩您點贊,關注。
我已經將本章收錄在專題裏,點擊下方專題,關注專欄,我會天天發表乾貨,本月我會持續輸入設計模式。
加油! 咱們下期再見!