行為型模式用于描述程序在運(yùn)行時復(fù)雜的流程控制,即描述多個類或?qū)ο笾g怎樣相互協(xié)作共同完成單個對象無法單獨(dú)完成的任務(wù),它涉及算法與對象間職責(zé)的分配。行為型模式分為類行為模式和對象行為模式:
-
類行為模式:采用繼承機(jī)制來在類間分派行為
-
對象行為模式:采用組合或聚合在對象間分配行為
由于組合關(guān)系或聚合關(guān)系比繼承關(guān)系耦合度低,滿足“合成復(fù)用原則”,所以對象行為模式比類行為模式具有更大的靈活性。
行為型模式分為:
- 模板方法模式
- 策略模式
- 命令模式
- 職責(zé)鏈模式
- 狀態(tài)模式
- 觀察者模式
- 中介者模式
- 迭代器模式
- 訪問者模式
- 備忘錄模式
- 解釋器模式
以上 11 種行為型模式,除了模板方法模式和解釋器模式是類行為型模式,其他的全部屬于對象行為型模式。
命令模式
定義:將一個請求封裝為一個對象,使發(fā)出請求的責(zé)任和執(zhí)行請求的責(zé)任分割開。這樣兩者之間通過命令對象進(jìn)行溝通,這樣方便將命令對象進(jìn)行存儲、傳遞、調(diào)用、增加與管理。
命令模式是一種行為設(shè)計(jì)模式**,它將請求轉(zhuǎn)換為一個包含與請求相關(guān)的所有信息的獨(dú)立對象**,該轉(zhuǎn)換讓你能夠根據(jù)不同的請求將方法參數(shù)化,延遲請求執(zhí)行或者將其放入隊(duì)列中,且能夠?qū)崿F(xiàn)可撤銷操作
解決的問題
- 客戶點(diǎn)菜是通過服務(wù)員,所以發(fā)送請求的責(zé)任屬于服務(wù)員
- 具體的菜品是廚師進(jìn)行烹飪,所以執(zhí)行請求的測試的屬于廚師
- 將發(fā)送請求的責(zé)任與執(zhí)行請求的責(zé)任分開
結(jié)構(gòu)
- 抽象命令類(Command)角色: 定義命令的接口,聲明執(zhí)行的方法。
- 具體命令(Concrete Command)角色:具體的命令,實(shí)現(xiàn)命令接口;通常會持有接收者,并調(diào)用接收者的功能來完成命令要執(zhí)行的操作。
- 實(shí)現(xiàn)者/接收者(Receiver)角色: 接收者,真正執(zhí)行命令的對象。任何類都可能成為一個接收者,只要它能夠?qū)崿F(xiàn)命令要求實(shí)現(xiàn)的相應(yīng)功能。
- 調(diào)用者/請求者(Invoker)角色: 要求命令對象執(zhí)行請求,通常會持有命令對象,可以持有很多的命令對象。這個是客戶端真正觸發(fā)命令并要求命令執(zhí)行相應(yīng)操作的地方,也就是說相當(dāng)于使用命令對象的入口。
實(shí)例
分析命令模式的角色在該案例中由誰來充當(dāng):
- 服務(wù)員: 就是調(diào)用者角色,由她來發(fā)起命令。
- 資深大廚: 就是接收者角色,真正命令執(zhí)行的對象。
- 訂單: 命令中包含訂單。
抽象命令類
public interface Command {
void execute();
}
具體命令類
public class OrderCommand implements Command{
private SeniorChef receiver;
private Order order;
public OrderCommand(SeniorChef receiver, Order order) {
this.receiver = receiver;
this.order = order;
}
@Override
public void execute() {
System.out.println(order.getDiningTable() + "桌的訂單:");
Map<String, Integer> foodDir = order.getFoodDir();
Set<String> keys = foodDir.keySet();
for (String foodName : keys) {
receiver.makeFood(foodName, foodDir.get(foodName));
}
System.out.println(order.getDiningTable() + "桌的飯準(zhǔn)備完畢?。。?);
}
}
/**
* 訂單類
*/
@Data
public class Order {
// 餐桌號碼
private int diningTable;
// 所下的餐品及份數(shù)
private Map<String,Integer> foodDir = new HashMap<>();
public void setFood(String name, int num) {
foodDir.put(name,num);
}
}
- 聚合了接收者
接收者:資深大廚
public class SeniorChef {
public void makeFood(String name,int num) {
System.out.println(num + "份" + name);
}
}
調(diào)用者:服務(wù)員
public class Waiter {
//持有多個命令對象
private List<Command> commands=new ArrayList<>();
public void setCommand(Command cmd) {
// 將命令類對象存儲到list集合中
commands.add(cmd);
}
// 發(fā)起命令功能: 喊 訂單來了
public void orderUp() {
System.out.println("美女服務(wù)員:大廚,新訂單來了。。。。");
for (Command command : commands) {
if(command != null) {
command.execute();
}
}
}
}
- 調(diào)用者中聚合了命令對象
- 我們這里調(diào)用者就將我們的命令對象放入了隊(duì)列中,這種我們的可以命令對象進(jìn)行操作,比如延遲執(zhí)行,當(dāng)然也可以做到了我們的撤銷等操作
測試
public class Client {
public static void main(String[] args) {
// 創(chuàng)建第二個訂單對象
Order order1 = new Order();
order1.setDiningTable(1);
order1.setFood("西紅柿雞蛋面",1);
order1.setFood("小杯可樂",2);
// 創(chuàng)建第二個訂單對象
Order order2 = new Order();
order2.setDiningTable(2);
order2.setFood("尖椒肉絲蓋飯",1);
order2.setFood("小杯雪碧",1);
//創(chuàng)建接收者對象 廚師
SeniorChef receiver = new SeniorChef();
//創(chuàng)建命令對象
OrderCommand orderCommand1 = new OrderCommand(receiver, order1);
OrderCommand orderCommand2 = new OrderCommand(receiver, order2);
// 創(chuàng)建調(diào)用者(服務(wù)員對象)
Waiter invoke = new Waiter();
invoke.setCommand(orderCommand1);
invoke.setCommand(orderCommand2);
//讓服務(wù)員發(fā)起命令
invoke.orderUp();
}
}
美女服務(wù)員:大廚,新訂單來了。。。。
1桌的訂單:
1份西紅柿雞蛋面
2份小杯可樂
1桌的飯準(zhǔn)備完畢?。?!
2桌的訂單:
1份尖椒肉絲蓋飯
1份小杯雪碧
2桌的飯準(zhǔn)備完畢?。?!
存在的問題
優(yōu)點(diǎn):
-
降低系統(tǒng)的耦合度。命令模式能將調(diào)用操作的對象與實(shí)現(xiàn)該操作的對象解耦。
-
增加或刪除命令非常方便。采用命令模式增加與刪除命令不會影響其他類,它滿足 “開閉原則”,對擴(kuò)展比較靈活。
-
可以實(shí)現(xiàn)宏命令。命令模式可以與組合模式結(jié)合,將多個命令裝配成一個組合命令,即宏命令。
-
方便實(shí)現(xiàn) Undo 和 Redo 操作。命令模式可以與后面介紹的備忘錄模式結(jié)合,實(shí)現(xiàn)命令的撤銷與恢復(fù)。
缺點(diǎn):
- 使用命令模式可能會導(dǎo)致某些系統(tǒng)有過多的具體命令類。
- 系統(tǒng)結(jié)構(gòu)更加復(fù)雜。
適用場景
- 系統(tǒng)需要將請求調(diào)用者和請求接收者解耦,使得調(diào)用者和接收者不直接交互。
- 系統(tǒng)需要在不同的時間指定請求、將請求排隊(duì)和執(zhí)行請求。
- 系統(tǒng)需要支持命令的撤銷 (Undo) 操作和恢復(fù) (Redo) 操作。
JDK 源碼 - Runnable
Runable 是一個典型命令模式,Runnable 擔(dān)當(dāng)命令的角色,Thread 充當(dāng)?shù)氖?strong>調(diào)用者,start 方法就是其執(zhí)行方法文章來源:http://www.zghlxwxcb.cn/news/detail-467283.html
- 調(diào)用者和接收者分離了
// 命令接口(抽象命令角色)
public interface Runnable {
public abstract void run();
}
// 調(diào)用者
public class Thread implements Runnable {
private Runnable target;
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
}
start 方法會調(diào)用一個 native 方法 start0(),調(diào)用系統(tǒng)方法,開啟一個線程。而接收者是對程序員開放的,可以自己定義接收者。文章來源地址http://www.zghlxwxcb.cn/news/detail-467283.html
/**
* jdk Runnable 命令模式
* TurnOffThread:屬于具體命令
*/
public class TurnOffThread implements Runnable{
private Receiver receiver;
public TurnOffThread(Receiver receiver) {
this.receiver = receiver;
}
public void run() {
receiver.turnOFF();
}
}
到了這里,關(guān)于第十五章行為性模式—命令模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!