一文理解设计模式--命令模式(Command)

it2026-09-03  1

命令模式(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

缺点

和设计者模式一样,可能需要大量具体命令类,因为每一个命令都是一个类
最新回复(0)