《Head First设计模式》第六章笔记-命令模式
封裝調用-命令模式
?
命令模式可將“動作的請求者”從“動作的執行者”對象中解耦。
本篇中將不再描述書中所引入的“巴斯特家電自動化公司”的遙控器控制案例,而使用簡單易懂的餐廳案例。
在開始之前,讓我們通過一個現實中的例子來了解命令模式。
理解命令模式
讓我們回到餐廳,研究顧客、女招待、訂單,以及快餐廚師之間的交互。通過這樣的互動,你將體會到命令模式所涉及的對象,也會知道它們之間如何被解耦。
將以上流程代入到編程的對象中進一步思考對象與方法之間的關系:
分析餐廳對應的角色與職責
1、顧客:發出請求的對象。
2、訂單:封裝了準備餐點的請求。
3、女招待:接收訂單,然后調用訂單的orderUp方法,將訂單提交到柜臺,無需知道訂單細節。
4、廚師:收到訂單后,按訂單實現對應餐點的所有方法制作餐點。
從餐廳到命令模式
命令模式類圖
- Command:定義命令的接口,聲明執行的方法。
- ConcreteCommand: 具體的命令, 實現命令接口;通常會持有接收者,并調用接收者的功能來完成命令要執行的操作。
- Receiver:接收者,真正執行命令的對象。任何類都可能成為一個接收者,只要它能夠實現命令要求實現的相應功能。
- Invoker:要求命令對象執行請求,通常會持有命令對象,可以持有很多的命令對象。這個是客戶端真正觸發命令并要求命令執行相應操作的地方,也就是說相當于使用命令對象的入口。
- Client: 創建具體的命令對象,并且設置命令對象的接收者。注意這個不是我們常規意義上的客戶端,而是在組裝命令對象和接收者,或許,把這個Client稱為裝配者會更好理解,因為真正使用命令的客戶端是從Invoker來觸發執行。
命令模式定義:將“請求”封裝成對象,以便使用不同的請求、隊列或者日志來參數化其它對象。命令模式也支持可撤銷的操作。
實現命令接口:
| 1 2 3 | public abstract class Command{ ????public abstract void Execute(); } |
OrderCommand:具體的命令,繼承自Command抽象類
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class OrderCommand?implements Command{ ????//持有接受者對象 ????SeniorChef receiver; ????Order order; ????public OrderCommand(SeniorChef receiver, Order order){ ????????this.receiver = receiver; ?????????this.order = order; ????} ????public override?void Execute(){ ????????Console.WriteLine("{0}桌的訂單:", order.DiningTable); ????????foreach (string item in order.FoodDic.Keys){ ????????????//通常會轉調接收者對象的相應方法,讓接收者來真正執行功能 ????????????receiver.MakeFood(order.FoodDic[item],item); ????????} ????????Thread.Sleep(2000);//停頓一下 模擬做飯的過程 ????????Console.WriteLine("{0}桌的飯弄好了", order.DiningTable); ????} } |
Invoker調用者,seniorChef:接收者
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | public class Waiter{ ????ArrayList commands =?null;//可以持有很多的命令對象 ????public Waiter(){ ????????commands =?new ArrayList(); ????} ????public void SetCommand(Command cmd){ ????????commands.Add(cmd); ????} ????//提交訂單 喊 訂單來了,廚師開始執行 ????public void OrderUp(){ ????????Console.WriteLine("美女服務員:叮咚,大廚,新訂單來了......."); ????????Console.WriteLine("資深廚師:收到"); ????????for (int i =?0; i < commands.Count; i++){ ????????????Command cmd = commands[i] as Command; ????????????if (cmd !=?null){ ????????????????cmd.Execute(); ????????????} ????????} ????} } |
| 1 2 3 4 5 | public class SeniorChef{ ????public void MakeFood(int num,string foodName){ ????????Console.WriteLine("{0}份{1}", num,foodName); ????} } |
訂單Order,封裝訂單內容,然后傳入OrderCommand,將訂單對象變為命令對象
| 1 2 3 4 5 6 | public class Order{ ????// 餐桌號碼 ????public int DiningTable { set; get; } ????// food key:飯名 value:多少份 ????public Dictionary FoodDic { set; get; } } |
測試端Program相當于Client角色
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | class Program{ ????public static void main(string[] args){ ????//program類 作為客戶端 ????//創建2個order ????Order order1 =?new Order(); ????order1.DiningTable =?1; ????order1.FoodDic =?new Dictionary() ; ????order1.FoodDic.Add("西紅柿雞蛋面",1); ????order1.FoodDic.Add("小杯可樂",2); ????Order order2 =?new Order(); ????order2.DiningTable =?3; ????order2.FoodDic =?new Dictionary(); ????order2.FoodDic.Add("尖椒肉絲蓋飯",?1); ????order2.FoodDic.Add("小杯雪碧",?1); ????//創建接收者 ????SeniorChef receiver=new SeniorChef(); ????//將訂單這個兩個消息封裝成命令對象 ????OrderCommand cmd1 =?new OrderCommand(receiver, order1); ????OrderCommand cmd2 =?new OrderCommand(receiver, order2); ????//創建調用者 waitor ????Waitor invoker =?new Waitor(); ????//添加命令 ????invoker.SetCommand(cmd1); ????invoker.SetCommand(cmd2); ????//將訂單帶到柜臺 并向廚師喊 訂單來了 ????invoker.OrderUp(); ????Console.Read(); ????} } |
總結
命令模式優點:
1.降低對象之間的耦合度。
2.新的命令可以很容易地加入到系統中。
3.可以比較容易地設計一個組合命令。
4.調用同一方法實現不同的功能
缺點:
使用命令模式可能會導致某些系統有過多的具體命令類。因為針對每一個命令都需要設計一個具體命令類,因此某些系統可能需要大量具體命令類,這將影響命令模式的使用。
適用環境:
1.系統需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互。
2.系統需要在不同的時間指定請求、將請求排隊和執行請求。
3.系統需要支持命令的撤銷(Undo)操作和恢復(Redo)操作。
4.系統需要將一組操作組合在一起,即支持宏命令。
總結
以上是生活随笔為你收集整理的《Head First设计模式》第六章笔记-命令模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关系数据库——视图/存储过程/触发器
- 下一篇: 《Head First设计模式》第二章笔