命令模式
日常生活中,我們出去吃飯都會遇到下面的場景。
定義: 將一個請求封裝為一個對象,使發(fā)出請求的責任和執(zhí)行請求的責任分割開。這樣兩者之間通過命令對象進行溝通,這樣方便將命令對象進行存儲、傳遞、調用、增加與管理。命令模式包含以下主要角色:
- 抽象命令類(Command)角色: 定義命令的接口,聲明執(zhí)行的方法。
- 具體命令(Concrete Command)角色:具體的命令,實現命令接口;通常會持有接收者,并調用接收者的功能來完成命令要執(zhí)行的操作。
- 實現者/接收者(Receiver)角色: 接收者,真正執(zhí)行命令的對象。任何類都可能成為一個接收者,只要它能夠實現命令要求實現的相應功能。
- 調用者/請求者(Invoker)角色: 要求命令對象執(zhí)行請求,通常會持有命令對象,可以持有很多的命令對象。這個是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應操作的地方,也就是說相當于使用命令對象的入口。
案例實現
我們以一個美團外賣接單的例子來實現命令模式,假設你開了一家外賣飯店,角色有老板、廚師和接到的訂單(命令類),
將上面的案例用代碼實現,那我們就需要分析命令模式的角色在該案例中由誰來充當。
- 老板: 就是調用者角色,由她來向后廚廚師發(fā)起做菜的命令。
- 大廚: 就是接收者角色,真正命令執(zhí)行的對象。
- 訂單: 命令,命令中就包含了訂單。
類圖如下:
代碼如下:
首先定義訂單類、接受者類(廚師):
// 訂單類
public class Order {
// 訂單
private long ID;
// 用來存儲餐名并記錄份數
private Map<String, Integer> foodDic = new HashMap<String, Integer>();
public long getID() {
return ID;
}
public void setID(long ID) {
this.ID = ID;
}
public Map<String, Integer> getFoodDic() {
return foodDic;
}
public void setFoodDic(String name, int num) {
foodDic.put(name,num);
}
}
// 廚師類
public class Chef {
public void makeFood(int num,String foodName){
System.out.println("已經做好"+num + "份" + foodName);
}
}
然后定義命令接口并和它的具體實現:
// 命令接口
public interface Command {
void execute(); // 命令執(zhí)行方法
}
// 具體訂單命令
public class OrderCommand implements Command{
// 命令接受者對象
private Chef receiver;
private Order order;
public OrderCommand(Chef receiver, Order order){
this.receiver = receiver;
this.order = order;
}
// 命令執(zhí)行方法:命令接受者處理命令
@Override
public void execute() {
System.out.println("訂單號:"+order.getID());
Set<String> keys = order.getFoodDic().keySet();
for (String key : keys) {
receiver.makeFood(order.getFoodDic().get(key),key);
}
try {
Thread.sleep(100);//停頓一下 模擬做飯的過程
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(order.getID() + "訂單的飯弄好了");
}
}
最后定義命令發(fā)出者(老板)類:
public class Boss {
private ArrayList<Command> commands;//老板美團可以接很多單,可以持有很多的命令對象
public Boss() {
commands = new ArrayList();
}
// 不斷接單
public void setCommand(Command cmd){
commands.add(cmd);
}
// 向后廚發(fā)出命令您有新的訂單,廚師開始執(zhí)行
public void orderUp() {
System.out.println("張師傅,該工作了,新訂單來了.......");
for (int i = 0; i < commands.size(); i++) {
Command cmd = commands.get(i);
if (cmd != null) {
cmd.execute();
}
}
}
}
客戶類測試:
public class Main {
public static void main(String[] args) {
//創(chuàng)建2個order
Order order1 = new Order();
order1.setID(1);
order1.getFoodDic().put("西紅柿雞蛋面",1);
order1.getFoodDic().put("小杯可樂",2);
Order order2 = new Order();
order2.setID(3);
order2.getFoodDic().put("尖椒肉絲蓋飯",1);
order2.getFoodDic().put("小杯雪碧",1);
//創(chuàng)建接收者
Chef receiver=new Chef();
//將訂單和接收者封裝成命令對象
OrderCommand cmd1 = new OrderCommand(receiver, order1);
OrderCommand cmd2 = new OrderCommand(receiver, order2);
//創(chuàng)建調用者 Boss 向后廚師傅發(fā)出做飯命令
Boss invoker = new Boss();
invoker.setCommand(cmd1); // 接單
invoker.setCommand(cmd2); // 接單
//將訂單帶到柜臺 并向廚師喊 訂單來了
invoker.orderUp();
}
}
結果輸出:
張師傅,該工作了,新訂單來了…
訂單號:1
已經做好1份西紅柿雞蛋面
已經做好2份小杯可樂
1訂單的飯弄好了
訂單號:3
已經做好1份尖椒肉絲蓋飯
已經做好1份小杯雪碧
3訂單的飯弄好了
優(yōu)點
- 降低系統(tǒng)的耦合度。命令模式能將調用操作的對象與實現該操作的對象解耦。
- 增加或刪除命令非常方便。采用命令模式增加與刪除命令不會影響其他類,它滿足“開閉原則”,對擴展比較靈活。
- 可以實現宏命令。命令模式可以與組合模式結合,將多個命令裝配成一個組合命令,即宏命令。
- 方便實現 Undo 和 Redo 操作。命令模式可以與后面介紹的備忘錄模式結合,實現命令的撤銷與恢復。
缺點
- 使用命令模式可能會導致某些系統(tǒng)有過多的具體命令類。
- 系統(tǒng)結構更加復雜。
使用場景
- 系統(tǒng)需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互。
- 系統(tǒng)需要在不同的時間指定請求、將請求排隊和執(zhí)行請求。
- 系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(Redo)操作。
JDK源碼解析
Runable是一個典型命令模式,Runnable擔當命令的角色,Thread充當的是調用者,start方法就是其執(zhí)行方法。文章來源:http://www.zghlxwxcb.cn/news/detail-798955.html
參考內容
傳智播客設計模式相關筆記(主要)文章來源地址http://www.zghlxwxcb.cn/news/detail-798955.html
到了這里,關于行為型設計模式——命令模式的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!