What
命令模式(Command Design Pattern)删豺,將請(qǐng)求(命令)封裝為一個(gè)對(duì)象,這樣可以使用不同的請(qǐng)求參數(shù)化其他對(duì)象(將不同請(qǐng)求依賴注入到其他對(duì)象)番宁,并且能夠支持請(qǐng)求(命令)的排隊(duì)執(zhí)行、記錄日志、撤銷等(附加控制)功能宪郊。
Why
命令模式具有以下優(yōu)點(diǎn):
- 降低系統(tǒng)的耦合度。
- 新的命令可以很容易地加入到系統(tǒng)中拖陆。
- 可以比較容易地設(shè)計(jì)一個(gè)命令隊(duì)列和宏命令(組合命令)弛槐。
- 可以方便地實(shí)現(xiàn)對(duì)請(qǐng)求的Undo和Redo。
When
在以下情況下可以使用命令模式:
- 系統(tǒng)需要將請(qǐng)求調(diào)用者和請(qǐng)求接收者解耦依啰,使得調(diào)用者和接收者不直接交互乎串。
- 系統(tǒng)需要在不同的時(shí)間指定請(qǐng)求、將請(qǐng)求排隊(duì)和執(zhí)行請(qǐng)求速警。
- 系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(fù)(Redo)操作叹誉。
- 系統(tǒng)需要將一組操作組合在一起,即支持宏命令坏瞄。
How
命令模式包含如下角色:
- Command類桂对,即所有命令類的接口類,定義接口方法execute()鸠匀。
- ConcreteCommand類,即具體的命令類逾柿,如移動(dòng)類(MoveCommand缀棍、SkillCommand),實(shí)現(xiàn)execute方法机错。
- Invoker類爬范,負(fù)責(zé)調(diào)用命令對(duì)象執(zhí)行請(qǐng)求,相關(guān)的方法叫做action(行動(dòng))方法弱匪。
- Reciever類青瀑,負(fù)責(zé)具體實(shí)施和執(zhí)行一個(gè)請(qǐng)求。任何一個(gè)類都可以成為接收者,實(shí)施和執(zhí)行請(qǐng)求的方法叫做action(行動(dòng))方法斥难。
- Client類枝嘶,創(chuàng)建一個(gè)具體命令ConcreteCommand對(duì)象并確定其接收者。
命令模式UML圖
今天哑诊,我們就來實(shí)現(xiàn)一個(gè)《王者榮耀》簡(jiǎn)陋版群扶,主要實(shí)現(xiàn)客戶端發(fā)送的指令(英雄的移動(dòng)和放大招都可以抽象為一個(gè)指令)發(fā)送至消息隊(duì)列中,然后服務(wù)端從消息隊(duì)列中取出命令進(jìn)行執(zhí)行镀裤。
首先竞阐,我們定義Command接口及其實(shí)現(xiàn)類:
public interface Command {
void execute();
}
public class MoveCommand implements Command {
/**
* target object
*/
private Receiver receiver;
/**
* target loction
*/
private double locX;
private double locY;
public MoveCommand(Receiver receiver, double locX, double locY) {
this.receiver = receiver;
this.locX = locX;
this.locY = locY;
}
@Override
public void execute() {
this.receiver.action();
System.out.println(String.format("Move to (%f, %f)", locX, locY));
}
}
public class SkillCommand implements Command {
private Receiver receiver;
public SkillCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
System.out.println(String.format("use skill: %s", receiver.getSkill()));
}
}
然后,實(shí)現(xiàn)接受對(duì)象類暑劝,內(nèi)部的action方法執(zhí)行真正的操作骆莹。
public class Receiver {
private String name;
private String skill;
public Receiver(String name, String skill) {
this.name = name;
this.skill = skill;
}
public String getName() {
return name;
}
public String getSkill() {
return skill;
}
public void action() {
System.out.println(String.format("%s do action", this.getName()));
}
}
接下來,定義調(diào)用類:
public class Invoker {
/**
* command obejct
*/
private Command command;
public Invoker(Command command) {
this.command = command;
}
/**
* action
*/
public void action() {
command.execute();
}
}
最后担猛,來個(gè)測(cè)試類幕垦,即客戶端類。
public class TestMain {
public static void main(String[] args) {
// create receiver object
Receiver receiver = new Receiver("Arthur", "回旋打擊");
// create the command object, and set the receiver object
Command command1 = new MoveCommand(receiver, 10.0, 20.0);
Command command2 = new SkillCommand(receiver);
Command command3 = new MoveCommand(receiver, 30.0, 30.0);
Command command4 = new SkillCommand(receiver);
Command command5 = new MoveCommand(receiver, 40.0, 40.0);
Command command6 = new SkillCommand(receiver);
// put the command to the queue
Queue<Command> queue = new LinkedList<>();
queue.offer(command1);
queue.offer(command2);
queue.offer(command3);
queue.offer(command4);
queue.offer(command5);
queue.offer(command6);
// get the command and create the invoker to action
while (!queue.isEmpty()) {
Command command = queue.poll();
Invoker invoker = new Invoker(command);
invoker.action();
System.out.println();
}
}
}
輸出如下:
Arthur do action
Move to (10.000000, 20.000000)
Arthur do action
use skill: 回旋打擊
Arthur do action
Move to (30.000000, 30.000000)
Arthur do action
use skill: 回旋打擊
Arthur do action
Move to (40.000000, 40.000000)
大功告成毁习!
代碼地址
寫在最后
如果你覺得我寫的文章幫到了你智嚷,歡迎點(diǎn)贊、評(píng)論纺且、分享盏道、贊賞哦,你們的鼓勵(lì)是我不斷創(chuàng)作的動(dòng)力~