主要解決在系統中,行爲請求者和行爲實現者緊耦合的問題。java
命令模式是一種行爲設計模式,它可將請求轉換爲一個包含與請求相關的全部信息的獨立對象。這個轉換會根據不一樣的請求將方法參數化、延遲請求執行或將其放入隊列中,且能實現可撤銷操做。git
今年五一五天假,不少小夥伴可能以及火燒眉毛地要出去玩了。出去除了看風景之外,最重要的就是體驗一下當地的美食。找到心儀的店,固然少不了排隊,排隊的同時服務員會給一個二維碼提早點餐了,當咱們選好了想要吃的美食,肯定下單,後臺系統自動將訂單打印給不一樣的廚師。github
這時,咱們的訂單就是一個命令,它在廚師製做以前一直在隊列中等待。命令包含製做這些美食的全部信息。廚師能夠根據這個訂單直接製做,不須要和咱們確認訂單信息。設計模式
今天,咱們就以掃碼點餐爲例,介紹一下命令模式。ide
command-pattern └─ src ├─ main │ └─ java │ └─ org.design.pattern.command │ ├─ model │ │ ├─ cook │ │ │ ├─ Cook.java │ │ │ └─ impl │ │ │ ├─ ChiefCook.java │ │ │ └─ CustomCook.java │ │ └─ dish │ │ ├─ Dish.java │ │ └─ impl │ │ ├─ BraisedIntestines.java │ │ ├─ FriedPeanuts.java │ │ ├─ LocalPotChicken.java │ │ └─ ShreddedCabbage.java │ └─ service │ └─ OrderService.java │ └─ impl │ └─ OrderServiceImpl.java └─ test └─ java └─ org.design.pattern.command └─ OrderServiceTest.java
廚師接口函數
/** * 廚師接口 */ public interface Cook { /** * 作飯 * @param dishName 菜名 */ void cooking(String dishName); }
主廚實體類測試
/** * 主廚 */ @Slf4j public class ChiefCook implements Cook { /** * 作飯 * * @param dishName 菜名 */ @Override public void cooking(String dishName) { log.info("主廚製做{}", dishName); } }
普通廚師實體類優化
/** * 普通廚師 */ @Slf4j public class CustomCook implements Cook { /** * 作飯 * * @param dishName 菜名 */ @Override public void cooking(String dishName) { log.info("普通廚師製做{}", dishName); } }
美食接口this
/** * 美食接口 */ public abstract class Dish { /** * 廚師 */ protected Cook cook; public Dish(Cook cook) { this.cook = cook; } /** * 製做 */ abstract public void cook(); }
九轉大腸實體類spa
/** * 九轉大腸 */ public class BraisedIntestines extends Dish { public BraisedIntestines(Cook cook) { super(cook); } /** * 製做 */ @Override public void cook() { this.cook.cooking("九轉大腸"); } }
油炸花生米實體類
/** * 油炸花生米 */ public class FriedPeanuts extends Dish { public FriedPeanuts(Cook cook) { super(cook); } /** * 製做 */ @Override public void cook() { this.cook.cooking("油炸花生米"); } }
地鍋雞實體類
/** * 地鍋雞 */ public class LocalPotChicken extends Dish { public LocalPotChicken(Cook cook) { super(cook); } /** * 製做 */ @Override public void cook() { this.cook.cooking("地鍋雞"); } }
手撕包菜實體類
/** * 手撕包菜 */ public class ShreddedCabbage extends Dish { public ShreddedCabbage(Cook cook) { super(cook); } /** * 製做 */ @Override public void cook() { this.cook.cooking("手撕包菜"); } }
點餐服務接口
/** * 點餐服務接口 */ public interface OrderService { /** * 點菜 * @param dish 菜 */ void order(Dish dish); /** * 下單 */ void placeOrder(); }
點餐服務實現類
/** * 點餐服務實現類 */ public class OrderServiceImpl implements OrderService { private List<Dish> dishList = new ArrayList<>(); /** * 點菜 * * @param dish 菜 */ @Override public void order(Dish dish) { dishList.add(dish); } /** * 下單 */ @Override public synchronized void placeOrder() { for (Dish dish : dishList) { dish.cook(); } dishList.clear(); } }
public class OrderServiceTest { @Test public void testPlaceOrder() { Cook chiefCook = new ChiefCook(); Cook customCook = new CustomCook(); Dish braisedIntestines = new BraisedIntestines(chiefCook); Dish localPotChicken = new LocalPotChicken(chiefCook); Dish friedPeanuts = new FriedPeanuts(customCook); Dish shreddedCabbage = new ShreddedCabbage(customCook); OrderService orderService = new OrderServiceImpl(); orderService.order(braisedIntestines); orderService.order(localPotChicken); orderService.order(friedPeanuts); orderService.order(shreddedCabbage); orderService.placeOrder(); } }
21:08:41.617 [main] INFO o.d.p.c.model.cook.impl.ChiefCook - 主廚製做九轉大腸 21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.ChiefCook - 主廚製做地鍋雞 21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.CustomCook - 普通廚師製做油炸花生米 21:08:41.620 [main] INFO o.d.p.c.model.cook.impl.CustomCook - 普通廚師製做手撕包菜 Process finished with exit code 0
觸發者(Invoker)—— 亦稱 「發送者(Sender)」類負責對請求進行初始化,其中必須包含一個成員變量來存儲對命令對象的引用。
發送者觸發命令,而不向接收者這集發送請求,且發送者並不負責建立命令對象:一般會經過構造函數從客戶端處獲取預先生成的命令。
具體命令(Concrete Commands)會實現各類類型的請求。
具體命令自身並不完成工做,而是會將調用委派給一個業務邏輯對象,固然爲了簡化代碼,也合併該對象。
接收對象執行方法所需的參數可聲明爲具體命令的成員對象,同時能夠將命令對象設爲不可變,僅容許經過構造早函數來對這些成員變量進行初始化。
接收者(Receiver)類包含部分業務邏輯。
基本上,任何對象均可以做爲接收者。絕大部分命令只處理如何將請求傳遞給接收者的細節,接收者自行完成實際的工做。
客戶端(Client)會建立並配置具體命令對象。
客戶端必須將接收者實體在內的全部請求參數傳遞給命令的構造函數,以後,生成的命令就能夠與一個或多個發送者相關聯。
設計模式並不難學,其自己就是多年經驗提煉出的開發指導思想,關鍵在於多加練習,帶着使用設計模式的思想去優化代碼,就能構建出更合理的代碼。
源碼地址:https://github.com/yiyufxst/design-pattern-java
參考資料:
小博哥重學設計模式:https://github.com/fuzhengwei/itstack-demo-design
深刻設計模式:https://refactoringguru.cn/design-patterns/catalog