什麼是命令模式
命令在生活中再常見不過了。就像小時候老師說寫不完作業不準回家,和暗戀的女生打鬧她叫你別跑一樣,這些都是命令。它們都有同一個特點:都包含一個命令的發送者、一個具體的命令以及一個命令接收者。在實際生活中,都是由命令發送方將命令直接傳遞給接收方讓其執行,這是一種強耦合關係。而在軟件設計中,爲了方便後期修改與維護,追求的是“低耦合,高內聚”。命令模式便提供了一種將強耦合關係轉化爲弱耦合關係的設計方法。
以去餐館喫飯爲例,顧客去餐館往往都是先叫來服務員,然後點餐喫飯,結賬走人。這裏點餐與結賬都可以看做是一個命令(要求喫飯,喫飽要求付錢)。如果像上面所說命令都必須由發送方直接傳遞給接收方,那找不到廚師可能就喫不上飯了。這不死心眼嘛,於是老闆請來一個服務員並交待:你的任務就是要記錄他們喫什麼並轉達給廚師,付錢的時候時候再給他們帶到收銀員那去。這樣一來,顧客有什麼需要只告訴服務員就好了,多省心。
在上面的描述中,其實已經用到了命令模式。顧客將命令交給服務員後就什麼都不用管了,其它的事都交給服務員處理。服務員根據顧客交給的不用命令決定去轉達給廚師做菜還是讓收銀員來收錢。整個就餐過程中顧客可以不知道廚師是誰,收銀員在哪兒。
模式的結構
可以將系統中的相關操作抽象成命令,使調用者與實現者相關分離。
命令模式包含以下主要角色:
- 抽象命令類:聲明執行命令的接口,擁有執行命令的抽象方法 execute()。
- 具體命令類:是抽象命令類的具體實現類,它擁有接收者對象,並通過調用接收者的功能來完成命令要執行的操作。
- 實現者/接收者類:執行命令功能的相關操作,是具體命令對象業務的真正實現者。
- 調用者/請求者類:是請求的發送者,它通常擁有很多的命令對象,並通過訪問命令對象來執行相關請求,它不直接訪問接收者。
模式的結構圖
模式的java實現
以上面去餐館就餐爲例,首先創建一個抽象命令的接口:
// 不管顧客有什麼請求,都作爲一種命令必須得到執行
public interface Command {
public void execute();
}
兩個具體的命令實現類:
//點餐
public class OrderFood implements Command {
// 做菜找廚師
private Cook cook;
public OrderFood() {
cook = new Cook();
}
@Override
public void execute() {
System.out.println("服務員通知廚師做菜...");
cook.action();
}
}
//付錢
public class Pay implements Command {
// 付錢找收銀員
private Cashier cashier;
public Pay() {
cashier = new Cashier();
}
@Override
public void execute() {
System.out.println("服務員通知收銀員收錢...");
cashier.action();
}
}
命令的調用者服務員,也是命令的發起者(顧客)與接收者(廚師或是收銀員)之間的中介者:
// 命令發送者服務員
public class Waiter {
private Command command;
public Command getCommand() {
return command;
}
// 服務員在傳達命令的時候要知道是顧客是要點餐還是要付錢
public void setCommand(Command command) {
this.command = command;
}
public void execute() {
// 訪問命令對象
command.execute();
}
}
最後命令總要有人執行,廚師做菜,收銀員收錢:
// 接收者廚師
public class Cook {
public void action() {
System.out.println("廚師開始做菜...");
}
}
// 接收者收銀員
public class Cashier {
public void action() {
System.out.println("收銀員準備收錢...");
}
}
最後就是命令的發起者,顧客類:
public class Customer {
public static void main(String[] args) {
System.out.println("進門首先叫來服務員");
Waiter waiter = new Waiter();
System.out.println("很餓,開始點餐");
OrderFood com1 = new OrderFood();
waiter.setCommand(com1);
waiter.execute();
System.out.println("喫飽了,通知服務員要求結賬");
Pay com2 = new Pay();
waiter.setCommand(com2);
waiter.execute();
}
}