命令模式(Command)
命令模式就是将命令包装成java对象,来保存命令历史记录和恢复上一个状态、重复执行命令,比如我们写代码的撤销(undo)、取消撤销(redo)
适用场景
- 需要
undo
、redo
功能,每个命令具有记录状态功能,比如代码写错了撤销、取消撤销 - 多个
命令依据不同情况排序
,根据排序后的命令组执行 - 在系统崩溃时可以
重新恢复
原来的状态。将命令持久化到日志,在崩溃后恢复需要从磁盘重新加载已记录的命令,并使用execute操作重新执行它们
角色说明
Command
:抽象命令类,所有命令需要实现或继承ConcreteCommand
:具体命令实现类Invoke
:调用者,命令操控者Receiver
:命令接收者(命令就是在这个对象生效)
代码示例
通过演示一个妖怪隐身、缩小、恢复原样的过程,来熟悉命令模式
- 命令抽象类
/**
* 命令抽象类,像编写命令一样操作
* 每个命令都可以恢复执行命令之前的状态
*
* @author July
* @date 2020/10/22
*/
public abstract class Command {
public abstract void execute(Receiver receiver);
public abstract void undo();
public abstract void redo();
@Override
public abstract String toString();
}
- 让妖怪隐身的命令
/**
* 隐形咒是一种具体的命令
*/
public class InvisibilityCommand extends Command {
private Receiver receiver;
@Override
public void execute(Receiver receiver) {
receiver.setVisibility(Visibility.INVISIBLE);
this.receiver = receiver;
}
@Override
public void undo() {
if (receiver != null) {
receiver.setVisibility(Visibility.VISIBLE);
}
}
@Override
public void redo() {
if (receiver != null) {
receiver.setVisibility(Visibility.INVISIBLE);
}
}
@Override
public String toString() {
return "invisible";
}
}
- 让妖怪变小的命令
public class ShrinkCommand extends Command {
private Size oldSize;
private Receiver receiver;
@Override
public void execute(Receiver receiver) {
oldSize = receiver.getSize();
receiver.setSize(Size.SMALL);
this.receiver = receiver;
}
@Override
public void undo() {
if (oldSize != null && receiver != null) {
Size temp = receiver.getSize();
receiver.setSize(oldSize);
oldSize = temp;
}
}
@Override
public void redo() {
undo();
}
@Override
public String toString() {
return "small";
}
}
- 命令接收者的抽象类
public abstract class Receiver {
private Size size;
private Visibility visibility;
public Size getSize() {
return size;
}
public void setSize(Size size) {
this.size = size;
}
public Visibility getVisibility() {
return visibility;
}
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
}
@Override
public abstract String toString();
/**
* Print status
*/
public void printStatus() {
System.out.println("接收者状态:" + String.format("[size=%s] [visibility=%s]", getSize(),
getVisibility()));
System.out.println();
}
}
- 妖怪
/**
* 妖怪,接收变小和隐身的命令
*/
public class GoblinReceiver extends Receiver {
public GoblinReceiver() {
setSize(Size.NORMAL);
setVisibility(Visibility.VISIBLE);
}
@Override
public String toString() {
return "GoblinReceiver";
}
}
- 控盘者(调用者)
/**
* 【关键的角色】命令的调用程序
*
* @author July
* @date 2020/10/22
*/
public class Invoker {
/**
* 用stack记录
*/
private Deque<Command> undoStack = new LinkedList<>();
private Deque<Command> redoStack = new LinkedList<>();
public Invoker() {
}
/**
* Cast spell
*/
public void call(Command command, Receiver receiver) {
System.out.println(this + "在" + receiver + " 上执行命令 " + command);
command.execute(receiver);
undoStack.offerLast(command);
}
/**
* 撤销最后的操作
*/
public void undo() {
if (!undoStack.isEmpty()) {
Command previousSpell = undoStack.pollLast();
redoStack.offerLast(previousSpell);
System.out.println(this + " undoes " + previousSpell + " command");
previousSpell.undo();
}
}
/**
* 重做最后的操作(重新执行命令)
*/
public void redo() {
if (!redoStack.isEmpty()) {
Command previousSpell = redoStack.pollLast();
undoStack.offerLast(previousSpell);
System.out.println(this + " redoes " + previousSpell + " command");
previousSpell.redo();
}
}
@Override
public String toString() {
return "Invoker";
}
}
- 测试类
public class App {
public static void main(String[] args) {
// 实例化一个调用角色
Invoker invoker = new Invoker();
// 命令执行的接收者(目标)
GoblinReceiver goblinReceiver = new GoblinReceiver();
// 打印接收者初始状态
goblinReceiver.printStatus();
// 对妖怪执行缩小命令
invoker.call(new ShrinkCommand(), goblinReceiver);
goblinReceiver.printStatus();
// 对妖怪执行隐身命令
invoker.call(new InvisibilityCommand(), goblinReceiver);
goblinReceiver.printStatus();
// 回退到上一步操作
invoker.undo();
goblinReceiver.printStatus();
// 回退到上一步操作
invoker.undo();
goblinReceiver.printStatus();
// 前进一步
invoker.redo();
goblinReceiver.printStatus();
// 前进一步
invoker.redo();
goblinReceiver.printStatus();
}
}
最终的执行结果:
接收者状态:[size=normal] [visibility=visible]
Invoker在GoblinReceiver 上执行命令 small
接收者状态:[size=small] [visibility=visible]
Invoker在GoblinReceiver 上执行命令 invisible
接收者状态:[size=small] [visibility=invisible]
Invoker undoes invisible command
接收者状态:[size=small] [visibility=visible]
Invoker undoes small command
接收者状态:[size=normal] [visibility=visible]
Invoker redoes small command
接收者状态:[size=small] [visibility=visible]
Invoker redoes invisible command
接收者状态:[size=small] [visibility=invisible]
优缺点
优点
- 降低系统
耦合度
,通过Invoker解耦Command和Receiver 扩展性高
,新命令可以很容易加入到系统中- 在不同时间指定、排队和执行请求,可以实现命令队列或
宏命令
(多个命令组合连续执行) - 很容易实现对命令的
undo
和redo
缺点
- 和设计者模式一样,可能需要
大量具体命令类
,因为每一个命令都是一个类
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/17886.html