又是一個點餐系統(原諒作者的吃貨屬性)。不過這次的點餐系統是個飯店的點餐系統。飯店的點餐系統有什麼不同嘛?大夥想想看,在大多數飯店中,當服務員已經接到顧客的點單,錄入到系統中後,根據不同的菜品,會有不同的背景反應。比如,飯店有涼菜間、熱菜間、主食間,那當服務員将菜品錄入到系統中後,涼菜間會列印出顧客所點的涼菜條目,熱菜間會列印出顧客所點的熱菜條目,主食間會列印出主食條目。那這個系統的背景模式該如何設計?當然,直接在場景代碼中加if…else…語句判斷是個方法,可這樣做又一次加重了系統耦合,違反了單一職責原則,遇到系統需求變動時,又會輕易違反開閉原則。是以,我們需要重新組織一下結構。
可以将該系統設計成前台服務員系統和背景系統,背景系統進一步細分成主食子系統,涼菜子系統,熱菜子系統。背景三個子系統設計如下:
前台服務員系統與背景系統的互動,我們可以通過指令的模式來實作,服務員将顧客的點單内容封裝成指令,直接對背景下達指令,背景完成指令要求的事,即可。前台系統建構如下:
前台系統中的notify接口直接調用指令中的execute接口,執行指令。指令類建構如下:
command類是個比較通過的類,foodcommand類是本例中涉及的類,相比于command類進行了一定的改造。由于背景系統中的執行函數都是cook,因而在foodcommand類中直接将execute接口實作,如果背景系統執行函數不同,需要在三個子指令系統中實作execute接口。這樣,背景三個指令類就可以直接繼承,不用進行修改了。(這裡子系統沒有變動,可以将三個子系統的指令廢棄不用,直接用foodcommand嗎?當然可以,各有利蔽。請讀者結合自身開發經驗,進行思考相對于自己業務場景的使用,哪種方式更好。)
為使場景業務精簡一些,我們再加一個菜單類來輔助業務,菜單類在本例中直接寫死。
業務場景如下:
列印如下:
waiter:add dish
waiter:nofify...
hotdish:cook yu-shiang shredded pork
hotdish:cook sauteed tofu, home style
cooldish:cook cucumber
mainfood:cook rice
指令模式的定義為:将一個請求封裝成一個對象,進而可以使用不同的請求将用戶端參數化,對請求排隊或者記錄請求日志,可以提供指令的撤銷和恢複功能。指令模式中通常涉及三類對象的抽象:receiver,command,invoker(本例中的waitersys)。
隻有一個invoker的指令模式也可以抽象成一個類似的“星形網絡”,但與之前介紹的中介者模式不同,單純的指令模式更像是一個輻射狀的結構,由invoker直接對receiver傳遞指令,而一般不反向傳遞,中介者模式“星形網絡”的中心,是個協調者,抽象結節間的資訊流全部或者部分是雙向的。
另外,指令模式的定義中提到了“撤銷和恢複功能”,也給了各位開發人員一個指令模式使用過程中的建議:各個receiver中可以設計一個復原接口,支援指令的“撤銷”。
優點:
1、低耦合:調用者和接收者之間沒有什麼直接關系,二者通過指令中的execute接口聯系;
2、擴充性好:新指令很容易加入,也很容易拼出“組合指令”。
應用場景:
1、觸發-回報機制的系統,都可以使用指令模式思想。如基于管道結構的指令系統(如shell),可以直接套用指令模式;此外,gui系統中的操作回報(如點選、鍵入等),也可以使用指令模式思想。
1、如果業務場景中指令比較多,那麼對應指令類和指令對象的數量也會增加,這樣系統會膨脹得很大。