目錄
一、基礎概念
二、UML類圖
三、角色設計
四、案例分析
4.1、基本實現(xiàn)
4.2、點餐案例?
五、總結
一、基礎概念
1、將一個請求封裝為一個對象,使您可以用不同的請求對客戶進行參數(shù)化。
2、對請求排隊或記錄請求日志,以及支持可撤銷的操作。
3、將命令對象與執(zhí)行命令的對象分離,實現(xiàn)調(diào)用者和接收者的解耦。
其中命令對象是關鍵,它包含了一個接收者和一個執(zhí)行操作的方法。該命令對象綁定一個接收者對象,并通過調(diào)用接收者相應的操作來完成執(zhí)行請求的功能。
二、UML類圖
三、角色設計
角色 | 描述 |
---|---|
抽象命令類 | 定義命令的接口,聲明執(zhí)行的方法 |
具體命令角色 | 具體命令類,實現(xiàn)了命令接口,綁定接收者,并實現(xiàn)執(zhí)行命令的操作 |
接收者類 | 知道如何實施與執(zhí)行一個請求相關的操作 |
調(diào)用者類 | 接收命令請求并執(zhí)行命令 |
客戶端類 | 創(chuàng)建命令對象并設定它的接收者 |
四、案例分析
4.1、基本實現(xiàn)
主要包含以下幾個部分:
1、Command抽象命令類:定義了命令的公共接口一般是一個execute()方法。
2、ConcreteCommand具體命令角色:實現(xiàn)了Command接口,是具體的命令類,包含對Receiver對象的引用。其execute()方法會調(diào)用Receiver的相應方法。
3、Receiver接收者類:命令對象Indirect調(diào)用的接收者對象。實現(xiàn)了具體的業(yè)務邏輯。
4、Invoker調(diào)用者類:請求的調(diào)用者。其持有Command對象的引用,并通過command.execute()間接調(diào)用Receiver。
5、Client客戶端類:創(chuàng)建Command和Receiver對象,并創(chuàng)建Invoker傳入Command對象,最后調(diào)用Invoker的invoke()方法觸發(fā)執(zhí)行。
這個實現(xiàn)讓調(diào)用者Invoker和接收者Receiver解耦,Invoker只與Command接口發(fā)生依賴,不需要知道具體的命令與接收者。
抽象命令類:
public interface Command {
/**
* 執(zhí)行方法
*/
void execute();
}
?接收者類:
public class Receiver {
/**
* 真正執(zhí)行命令相應的操作
*/
public void action(){
System.out.println("執(zhí)行操作");
}
}
具體命令角色類:
public class ConcreteCommand implements Command {
//持有相應的接收者對象
private Receiver receiver = null;
/**
* 構造方法
*/
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
@Override
public void execute() {
//通常會轉調(diào)接收者對象的相應方法,讓接收者來真正執(zhí)行功能
receiver.action();
}
}
調(diào)用者類:
public class Invoker {
/**
* 持有命令對象
*/
private Command command = null;
/**
* 構造方法
*/
public Invoker(Command command){
this.command = command;
}
/**
* 行動方法
*/
public void action(){
command.execute();
}
}
客戶端:?
public class Client {
public static void main(String[] args) {
//創(chuàng)建接收者
Receiver receiver = new Receiver();
//創(chuàng)建命令對象,設定它的接收者
Command command = new ConcreteCommand(receiver);
//創(chuàng)建請求者,把命令對象設置進去
Invoker invoker = new Invoker(command);
//執(zhí)行方法
invoker.action();
}
}
運行結果如下:
4.2、點餐案例?
這個點餐的命令模式案例,主要演示了幾個角色對象之間的關系:
1、Waiter是接收者對象,知道如何執(zhí)行點餐操作。
2、OrderCommand是命令對象,它封裝了一個點餐請求,綁定了接收者Waiter。可以調(diào)用execute()執(zhí)行點餐。
3、Customer是調(diào)用者對象,它通過命令對象indirect地執(zhí)行點餐請求??梢栽O定并觸發(fā)命令。
4、Client是客戶端,進行對象的創(chuàng)建和使用。
抽象命令類:
public interface Command {
public void execute();
}
服務員(接收者類):
public class Waiter {
public void takeOrder(String food) {
System.out.println("服務員:收到點餐,食物是:" + food);
}
}
點餐命令類(具體的命令類):
public class OrderCommand implements Command {
private Waiter waiter;
private String food;
public OrderCommand(Waiter waiter, String food) {
this.waiter = waiter;
this.food = food;
}
@Override
public void execute() {
waiter.takeOrder(food);
}
}
顧客(調(diào)用者類):
public class Customer {
private Command command;
public void setOrder(Command command) {
this.command = command;
}
public void orderUp() {
command.execute();
}
}
客戶端類:?
public class Client {
public static void main(String[] args) {
Waiter waiter = new Waiter();
Command cmd = new OrderCommand(waiter, "番茄炒蛋");
Customer customer = new Customer();
customer.setOrder(cmd);
customer.orderUp();
}
}
運行結果如下:
整個執(zhí)行流程是:
1、Client創(chuàng)建Waiter、OrderCommand、Customer對象。
2、Client把OrderCommand命令對象設置給Customer調(diào)用者。
3、Client請求Customer調(diào)用orderUp方法。
4、Customer的orderUp方法內(nèi)部將調(diào)用OrderCommand的execute。
5、OrderCommand的execute會調(diào)用其內(nèi)部綁定的Waiter的takeOrder方法。
6、這樣客戶的請求就通過命令對象傳達給服務員,進行點餐。
這實現(xiàn)了調(diào)用者與接收者的解耦,并且使用命令對象可以方便實現(xiàn)撤銷、重做、日志等功能。?
五、總結
優(yōu)點:
1、解耦了命令的發(fā)出者和執(zhí)行者:發(fā)出命令的對象只需要知道命令接口,不需要知道具體的命令執(zhí)行者。
2、可以較容易地設計一個命令隊列和宏命令:通過命令隊列可以對命令進行排隊,而宏命令可以執(zhí)行一系列的命令。
3、可以較容易實現(xiàn)命令的撤銷和重做:通過保存執(zhí)行過的命令對象,可以方便地實現(xiàn)回退。
缺點:
1、可能產(chǎn)生很多具體的命令類:因為每一個命令都需要一個具體的命令類,所以如果命令種類很多,會導致類的個數(shù)增加很多。
2、系統(tǒng)可能要慢一點,因為每次執(zhí)行命令時,都需要先創(chuàng)建命令對象。
應用場景:
1、需要對操作進行記錄、撤銷/重做、事務等處理的場景。命令模式可以方便實現(xiàn)這些功能。
2、需要將請求調(diào)用者和請求接收者解耦的場景。命令模式可以使兩者獨立變化。
3、需要把操作封裝成對象傳遞和存儲的場景。命令模式可以把操作轉換為對象。
4、需要對操作進行排隊或記錄日志、支持事務等功能的場景。可以用命令隊列實現(xiàn)排隊,用命令對象記錄日志。
5、需要支持向組合系統(tǒng)中添加新命令的場景。命令模式使新增命令比較方便。
6、需要對系統(tǒng)進行狀態(tài)恢復的場景??梢岳妹顚ο髮崿F(xiàn)狀態(tài)恢復。
7、需要實現(xiàn)宏命令、也就是組合命令的場景。命令模式可以方便實現(xiàn)宏命令。?
符合的設計原則:
1、開閉原則(Open-Closed Principle)
命令模式中,命令的執(zhí)行者與發(fā)出者是解耦的,發(fā)出者只知道命令接口,具體的實現(xiàn)執(zhí)行者可以新增而不需要修改發(fā)出者。這樣就滿足了開閉原則。
2、單一職責原則(Single Responsibility Principle)
命令模式把請求的發(fā)出者和執(zhí)行者進行了分離,發(fā)出者負責發(fā)出命令請求,執(zhí)行者負責具體執(zhí)行,職責劃分明確,都滿足單一職責原則。
3、組合復用原則(Composite Reuse Principle)
命令模式可以方便地將多個命令組合成一個組合命令,滿足組合復用原則。
4、里氏替換原則(Liskov Substitution Principle)文章來源:http://www.zghlxwxcb.cn/news/detail-559091.html
命令模式中抽象命令類規(guī)定了接口,具體命令類都遵循這個接口,滿足里氏替換原則。文章來源地址http://www.zghlxwxcb.cn/news/detail-559091.html
到了這里,關于Java設計模式之行為型-命令模式(UML類圖+案例分析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!