What
命令模式(Command Design Pattern),将请求(命令)封装为一个对象,这样可以使用不同的请求参数化其他对象(将不同请求依赖注入到其他对象),并且能够支持请求(命令)的排队执行、记录日志、撤销等(附加控制)功能。
Why
命令模式具有以下优点:
- 降低系统的耦合度。
- 新的命令可以很容易地加入到系统中。
- 可以比较容易地设计一个命令队列和宏命令(组合命令)。
- 可以方便地实现对请求的Undo和Redo。
When
在以下情况下可以使用命令模式:
- 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
- 系统需要在不同的时间指定请求、将请求排队和执行请求。
- 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
- 系统需要将一组操作组合在一起,即支持宏命令。
How
命令模式包含如下角色:
- Command类,即所有命令类的接口类,定义接口方法execute()。
- ConcreteCommand类,即具体的命令类,如移动类(MoveCommand、SkillCommand),实现execute方法。
- Invoker类,负责调用命令对象执行请求,相关的方法叫做action(行动)方法。
- Reciever类,负责具体实施和执行一个请求。任何一个类都可以成为接收者,实施和执行请求的方法叫做action(行动)方法。
- Client类,创建一个具体命令ConcreteCommand对象并确定其接收者。
今天,我们就来实现一个《王者荣耀》简陋版,主要实现客户端发送的指令(英雄的移动和放大招都可以抽象为一个指令)发送至消息队列中,然后服务端从消息队列中取出命令进行执行。
首先,我们定义Command接口及其实现类:
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()));
}
}
然后,实现接受对象类,内部的action方法执行真正的操作。
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()));
}
}
接下来,定义调用类:
public class Invoker {
/**
* command obejct
*/
private Command command;
public Invoker(Command command) {
this.command = command;
}
/**
* action
*/
public void action() {
command.execute();
}
}
最后,来个测试类,即客户端类。
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)
大功告成!
代码地址
写在最后
如果你觉得我写的文章帮到了你,欢迎点赞、评论、分享、赞赏哦,你们的鼓励是我不断创作的动力~