介紹:
命令模式是一種行為型模式。將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而讓用戶使用不同的請(qǐng)求把客戶端參數(shù)化;對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,以及支持可撤銷的操作。
備注:所謂的參數(shù)化,使用端使用執(zhí)行同一個(gè)請(qǐng)求,但是為請(qǐng)求配置不同的命令對(duì)象,那就會(huì)執(zhí)行不同的功能。例如:使用者按下一個(gè)按鈕,到底是開機(jī)還是重啟,那要看參數(shù)化配置的是哪一個(gè)具體的按鈕對(duì)象。
類圖:

Receiver(接受者角色):負(fù)責(zé)具體實(shí)施一個(gè)請(qǐng)求,執(zhí)行具體邏輯的角色。
Command(命令角色):定義好命令的接口,用來約束所有的命令對(duì)象。
ConcreteCommand(具體命令角色):實(shí)現(xiàn)Command接口,在execute方法中調(diào)用接受者角色的相關(guān)方法。
Invoker(請(qǐng)求者角色):調(diào)用命令對(duì)象執(zhí)行具體請(qǐng)求。
用法:
? 需要對(duì)行為進(jìn)行記錄、撤銷或重做、事務(wù)等處理時(shí)
? 抽象出待執(zhí)行的動(dòng)作以參數(shù)化某對(duì)象。類似過程設(shè)計(jì)中的回調(diào)機(jī)制,而命令模式是回調(diào)機(jī)制的一個(gè)面向?qū)ο蟮奶娲?/p>
個(gè)人理解:
? 命令模式核心就是將各種請(qǐng)求封裝成一個(gè)命令對(duì)象。命令對(duì)象作為一個(gè)“中間人”解耦行為請(qǐng)求者與行為執(zhí)行者。
? 用法中提到的進(jìn)行記錄、撤銷或重做、事務(wù)等處理,描述的是一些稍微復(fù)雜點(diǎn)的業(yè)務(wù),行為請(qǐng)求者實(shí)現(xiàn)一個(gè)功能時(shí)可能并不是立即執(zhí)行,甚至還需要做一些邏輯管理,這時(shí)候就需要考慮使用命令模式了。
例子:
例子1 我們使用電腦的時(shí)候,開機(jī)、關(guān)機(jī)、重啟都是作為系統(tǒng)的一條命令,用這個(gè)例子簡單介紹命令模式的結(jié)構(gòu)。
例子2 命令模式的用法中提到是回調(diào)機(jī)制的一個(gè)替代品,
1、簡單使用命令模式
1.1、定義命令接口Command接口
public interface Command {
void execute(); //執(zhí)行命令
}
約束好所有命令子類,必須實(shí)現(xiàn)execute()方法。
1.2、實(shí)現(xiàn)接受者角色Receiver,負(fù)責(zé)具體邏輯的實(shí)現(xiàn)
分別是關(guān)機(jī)、重啟、取消三個(gè)操作的具體實(shí)現(xiàn),這里我們簡單輸出一下:
public class Receiver {
public void shutdown(){
System.out.println("執(zhí)行關(guān)機(jī)操作");
System.out.print("開始關(guān)機(jī)....");
}
public void restart(){
System.out.println("執(zhí)行重啟操作");
System.out.print("開始關(guān)機(jī)....");
System.out.print("開始開機(jī)....");
}
public void cancel(){
System.out.print("取消操作");
}
}
1.3、實(shí)現(xiàn)命令子類ConcreteCommand
命令子類作為“中間人”,負(fù)責(zé)執(zhí)行Recevier相關(guān)方法。
public class RestartCommand implements Command {
private Receiver receiver;
public RestartCommand(Receiver receiver){
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println("命令角色執(zhí)行重啟命令");
receiver.restart();
}
}
省略ShutdownCommand類與CancelCommand類,結(jié)構(gòu)雷同。
1.4、創(chuàng)建Invoker,負(fù)責(zé)調(diào)用命令對(duì)象執(zhí)行請(qǐng)求
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action() {
System.out.println("調(diào)用者執(zhí)行命令");
command.execute();
}
}
Invoker作為命令的調(diào)用者,讓適合的命令對(duì)象執(zhí)行命令。
1.5、測試與實(shí)現(xiàn)
public class Test {
public static void main(String[] args) {
//構(gòu)造一個(gè)接受者對(duì)象
Receiver receiver = new Receiver();
//根據(jù)接受者對(duì)象創(chuàng)建一條命令
Command command = new RestartCommand(receiver);
//根據(jù)具體命令對(duì)象構(gòu)造請(qǐng)求者
Invoker invoker = new Invoker(command);
//執(zhí)行命令
invoker.action();
}
}
調(diào)用者執(zhí)行命令
命令角色執(zhí)行重啟命令
執(zhí)行重啟操作
開始關(guān)機(jī)....
開始開機(jī)....
關(guān)機(jī)重啟的例子簡單實(shí)現(xiàn)就完成了。讀到這里只是能體會(huì)到這個(gè)模式能解耦和具體結(jié)構(gòu),實(shí)際開發(fā)中用處不怎么大。例如,我們關(guān)機(jī)的時(shí)候通常會(huì)遇到以下情況:某個(gè)應(yīng)用程序還卡住了,關(guān)不了機(jī),重啟不了,這種情況怎么處理呢?
1.6、改進(jìn)一下Invoker
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action(boolean process) {
if (process){
System.out.print("進(jìn)程還沒退出,終止命令!");
return;
}
System.out.println("調(diào)用者執(zhí)行命令");
command.execute();
}
}
在action()方法加多個(gè)邏輯,判斷后臺(tái)進(jìn)程是否全部退出。我們發(fā)現(xiàn),Invoker請(qǐng)求者負(fù)責(zé)接受命令對(duì)象,并作出邏輯判斷,最后調(diào)用命令對(duì)象,甚至直接理解成它是一個(gè)命令管理者CommandController。
2、代替回調(diào)機(jī)制
我另外一篇文章詳細(xì)分析過回調(diào)機(jī)制,觀察者模式——監(jiān)聽與回調(diào),大家可以去看看。
下面簡單寫一下回調(diào)機(jī)制:
2.1、回調(diào)類
public interface ICallBack {
void callback();
}
2.2、需要執(zhí)行回調(diào)的類
public class A {
private ICallBack callBack;
public void setCallBack(ICallBack callBack){
this.callBack = callBack;
}
public void doSomething(){
System.out.print("do something!");
if (callBack != null){
callBack.callback();
}
}
}
2.3、實(shí)現(xiàn)
public class Client {
public static void main(String[] args) {
A a = new A();
a.setCallBack(new ICallBack() {
@Override
public void callback() {
System.out.print("執(zhí)行回調(diào)");
}
});
a.doSomething();
}
}
2.4、命令模式代替回調(diào)機(jī)制
public class ConcreteCommand implements ICallBack{
@Override
public void callback() {
System.out.print("執(zhí)行回調(diào)");
}
}
public class Client {
public static void main(String[] args) {
A a = new A();
a.setCallBack(new ConcreteCommand());//改了這里
a.doSomething();
}
}
回調(diào)機(jī)制:回調(diào)(Callback)函數(shù)是指函數(shù)先在某處注冊(cè),而它將在稍后某個(gè)需要的時(shí)候被調(diào)用,它實(shí)際上是一種參數(shù)化機(jī)制。
命令模式:命令模式的設(shè)計(jì)意圖就是“將一個(gè)請(qǐng)求封裝為一個(gè)對(duì)象,從而使用戶可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化”。
看下代碼,用具體命令對(duì)象類代替了匿名類回調(diào)函數(shù),同樣都是參數(shù)化的配置機(jī)制,就稱為代替了。本質(zhì)上,以上其實(shí)是兩種回調(diào)的寫法。
總結(jié):
? 命令模式理解上比較簡單,但使用上相對(duì)來說比較繁瑣,一個(gè)簡單的調(diào)用關(guān)系被解耦成多個(gè)部分。
? 用命令模式的參數(shù)化概念再回顧一下回調(diào)
? 在備忘錄模式中同樣提到撤銷與重做這個(gè)業(yè)務(wù)。如果在某個(gè)系統(tǒng)使用命令模式時(shí),需要實(shí)現(xiàn)命令的撤銷功能,那么命令模式可以使用備忘錄模式來存儲(chǔ)可撤銷操作的狀態(tài)。
感謝您的閱讀~
轉(zhuǎn)載請(qǐng)注明出處喔:http://m.itdecent.cn/p/1a6767821e9d
推薦閱讀
基礎(chǔ)篇:
設(shè)計(jì)模式前篇之——UML類圖必會(huì)知識(shí)點(diǎn)
設(shè)計(jì)模式前篇之——一起過一下面向?qū)ο蟮母拍?/a>
創(chuàng)建型模式:
簡易理解設(shè)計(jì)模式之:簡單工廠模式——來試試接入支付功能
簡易理解設(shè)計(jì)模式之:工廠方法模式——數(shù)據(jù)存儲(chǔ)例子
簡易理解設(shè)計(jì)模式之:抽象工廠模式——更換數(shù)據(jù)庫例子
簡易理解設(shè)計(jì)模式之:建造者模式——學(xué)習(xí)使用“鏈?zhǔn)秸{(diào)用”
簡易理解設(shè)計(jì)模式之:原型模式——深、淺拷貝的概念
簡易理解設(shè)計(jì)模式之:單例模式——單例模式的幾種常用寫法
結(jié)構(gòu)型模式:
簡易理解設(shè)計(jì)模式之:適配器模式——Android列表視圖控件設(shè)計(jì)方式
簡易理解設(shè)計(jì)模式之:橋接模式——穿衣服經(jīng)典案例2
簡易理解設(shè)計(jì)模式之:組合模式——實(shí)現(xiàn)View中的樹狀結(jié)構(gòu)
簡易理解設(shè)計(jì)模式之:裝飾模式——穿衣服經(jīng)典案例
簡易理解設(shè)計(jì)模式之:外觀模式——第三方SDK的幫助類
簡易理解設(shè)計(jì)模式之:享元模式——五子棋游戲例子
簡易理解設(shè)計(jì)模式之:代理模式——iOS視圖控件設(shè)計(jì)方式
行為型模式:
簡易理解設(shè)計(jì)模式之:策略模式——優(yōu)化一下支付功能
簡易理解設(shè)計(jì)模式之:模板方法模式——Android中的BaseActivity基類
簡易理解設(shè)計(jì)模式之:觀察者模式——監(jiān)聽與回調(diào)
簡易理解設(shè)計(jì)模式之:狀態(tài)模式——優(yōu)化登錄操作
簡易理解設(shè)計(jì)模式之:備忘錄模式——Word文檔的工作原理
簡易理解設(shè)計(jì)模式之:迭代器模式——遍歷對(duì)象的好幫手
簡易理解設(shè)計(jì)模式之:命令模式——實(shí)現(xiàn)命令的參數(shù)化配置
簡易理解設(shè)計(jì)模式之:責(zé)任鏈模式——OA中請(qǐng)假流程示例
簡易理解設(shè)計(jì)模式之:中介者模式——多人聊天室例子
簡易理解設(shè)計(jì)模式之:解釋器模式——語言和文法
簡易理解設(shè)計(jì)模式之:訪問者模式——員工考核例子