命令模式
基本介绍
1.将 Invoker 与 Receiver 解耦,Invoker 只要调用 ConcreteCommand 对象的 execute 方法让接收者执行请求的动作,ConcreteCommand 对象起到了纽带桥梁的作用,即解耦是通过命令对象实现的
2.将一个请求封装为一个对象,以便使用不同参数来表示不同的请求,同时也支持可撤销的操作
角色
1.Command:抽象命令角色,是接口或抽象类,包含所有需要执行的命令:execute(执行)、undo(撤销)
2.ConcreteCommand:具体命令角色,继承 / 实现 Command,聚合一个 Receiver 对象,将其与一个动作绑定,调用 Receiver 相应的操作,实现execute(执行)、undo(撤销)
(1)NoCommand:空命令角色,继承 / 实现 Command,用于初始化 Invoker 每个 Command 数组,简化操作,省去对 null 的判断
3.Invoker:命令调用角色
(1)聚合复数 Command 数组,存放不同功能的 ConcreteCommand 对象
(2)聚合一个 Command 对象(undoCommand),用于撤销上一个命令,undoCommand 可以是 Command 链表,实现多次撤销
(3)构造器用 NoCommand 对象初始化(填充)Command 数组
(4)SetCommand 设置 Command 数组中下标对应的命令
(5)不同方法调用不同的 Command 数组,根据下标调用 Command 数组的 ConcreteCommand 对象,undoCommand 记录本轮操作,用于撤销
(6)设置一个方法可以调用 undoCommand,撤销上个命令
4.Receiver:命令执行角色,知实施和执行一个请求相关的操作
事项
1.优点
(1)让对象之间的调用关系更加灵活,实现解耦
(2)只要把命令对象放到命令列队,就可以多线程的执行命令
(3)容易实现对请求的撤销和重做
2.缺点:可能导致某些系统有过多的具体命令类,增加了系统的复杂度
3.空命令也是一种设计模式,省去了判断 null 的操作
4.应用场景:界面按钮、模拟CMD(DOS命令) 订单的撤销 / 恢复、触发 - 反馈机制
外观模式、命令模式
1.外观模式
(1)简化操作,封装内部,不符合开闭原则,新增需要修改外观类
(2)外观模式无法穿透外观类(或接口)去细粒度的控制内部的执行顺序或某些特殊的逻辑,像只有一个按钮的遥控器,这一个按钮执行多个设定好顺序的开关操作,并且中间不能撤回
2.命令模式
(1)对命令调用者和命令执行者进行解耦,符合开闭原则
(2)命令模式能细粒度的控制每个按钮的执行顺序,像一个多按钮的遥控器,每个按钮是一个命令,使用某些按钮进行开关操作,还支持等待执行、执行撤回等操作
代码示例
import java.util.LinkedList;
public class Client {//客户端
public static void main(String[] args) {
Receiver receiver = new Receiver();//创建命令执行者
ConcreteCommand1 concreteCommand1 = new ConcreteCommand1(receiver);//传入命令执行者,创建具体命令1对象
ConcreteCommand2 concreteCommand2 = new ConcreteCommand2(receiver);//传入命令执行者,创建具体命令2对象
Invoker invoker = new Invoker();
invoker.SetCommand(0, concreteCommand1, concreteCommand2);
invoker.undo();
invoker.invokeCommand1(0);
invoker.undo();
invoker.invokeCommand2(0);
invoker.undo();
invoker.undo();
}
}
interface Command {//命令接口
void execute();//执行操作
void undo();//撤销操作
}
class Invoker {//命令调用者
private Command[] command1;
private Command[] command2;
private LinkedList<Command> undoCommand = new LinkedList<>();
public Invoker() {
command1 = new Command[5];
command2 = new Command[5];
for (int i = 0; i < 5; i++) {
command1[i] = new NoCommand();
command2[i] = new NoCommand();
}
}
public void SetCommand(int no, Command command1, Command command2) {
this.command1[no] = command1;
this.command2[no] = command2;
}
public void invokeCommand1(int no) {
command1[no].execute();
undoCommand.addLast(command1[no]);
}
public void invokeCommand2(int no) {
command2[no].execute();
undoCommand.addLast(command2[no]);
}
public void undo() {
if (undoCommand.peekLast() != null) {
undoCommand.pollLast().undo();
} else {
System.out.println("已回退到初始状态");
}
}
}
class Receiver {//命令执行者
//命令1是命令2的反操作
public void command1() {
System.out.println("执行命令1");
}
//命令2是命令1的反操作
public void command2() {
System.out.println("执行命令2");
}
}
class ConcreteCommand1 implements Command {//具体命令类1
public Receiver receiver;//聚合命令执行者
public ConcreteCommand1(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.command1();
}
@Override
public void undo() {
receiver.command2();
}
}
class ConcreteCommand2 implements Command {//具体命令类2
public Receiver receiver;//聚合命令执行者
public ConcreteCommand2(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.command2();
}
@Override
public void undo() {
receiver.command1();
}
}
class NoCommand implements Command {//空命令
@Override
public void execute() {
}
@Override
public void undo() {
}
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战