【学习】理解命令模式

照例先搬上来 Head First Design Patterns 中的定义,命令模式将请求封装为对象,从而允许使用不同的请求,队列或日志请求参数化其他对象,并支持可撤销操作。
在这里插入图片描述

是不是很抽象? 放个类图来理解一下它的组成
在这里插入图片描述

  • Client(客户):负责创建一个具体的命令(Concrete Command)
  • Invoker(调用者):调用者持有一个命令对象,并在某个时刻调用命令对象的 execute() 方法。
  • Command(命令接口):包含命令对象的 execute() 方法和 undo() 方法。
  • ConcreteCommand(具体命令):实现命令接口。包括两个操作,执行命令和撤销命令。
  • Receiver(接收者):接受命令并执行。

课本里举了在餐厅的例子,顾客到了餐厅,在服务员的帮助下点完餐,然后由服务员将点餐的内容告知给厨师,厨师再根据菜单做出相应的美味佳肴。在这个例子里,顾客就是 client,服务员就是 invoker,顾客点的菜就是 concrete command, 厨师就是 receiver,invoker 像是客户和对应命令执行者之间的中间,客户会告诉它需要干什么,它接到这个请求之后会告知给相应的命令对象,最后命令对象接到通知后就会执行命令。

代码
基本功能实现

//命令接口
public interface Command {
  public void execute ();
}
//第一个命令对象
public class LightOnCommand implements Command {
  Light light;
  public LightOnCommand (Light light) {
    this.light = light;
  }
  public void execute () {
    light.on();
  }
}
//使用命令对象
public class SimpleRemoteControl {
  Command slot;
  public SimpleRemoteControl () { }
  public void setCommand(Command command) {
    slot = command;
  }
  public void buttonWasPressed() {
    slot.execute();
  }
}
//测试该遥控功能
public class RemoteControlTest {
  public static void main(String[] args) {
    SimpleRemoteControl remote = new SimpleRemoteControl();
    Light light = new Light(); //被控制的对象,命令的作用者
    LightOnCommand lightOn = new LightOnCommand(light); //具体的命令
    
    remote.setCommand(lightOn);
    remote.buttonWasPressed();
  }
}

添加了一系列指令的遥控器,这里先介绍一下null object,很tricking的一种实现
在这里插入图片描述

//一系列的指令
public class RemoteControl{
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControl(){
        onCommands = new Command[7];
        offCommands = new Command[7];
        ...;//初始化onCommands offCommands和undoCommand都为noCommand
    }

    public void setCommand(int slot, Command onCommand, Command offCommand){
         onCommands[slot] = onCommand;
         ...;
    }

   public void onButtonWasPushed (int slot){
   		onCommands[slot].execute();
		undoCommand = onCommand[slot];
   }

   ...;
}

//添加undo功能
public interface Command {
	public void execute ();
  	public void undo ();
}

课本最后还介绍了宏命令(macro command)就是一系列命令的组合,只需按一个按钮,实现命令的批处理,这个功能实现起来比较简单也就不再多说了。

下面的部分个人理解的不是很多,摘录于引用三:
应用场景

1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队(如:线程池+工作队列)和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起,即支持宏命令。

适用场景

1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队(如:线程池+工作队列)和执行请求。 系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
3.系统需要将一组操作组合在一起,即支持宏命令。

优缺点:
优点:

1.降低系统的耦合度:Command模式将调用操作的对象与知道如何实现该操作的对象解耦。
2.Command是头等的对象。它们可像其他的对象一样被操纵和扩展。
3.组合命令:你可将多个命令装配成一个组合命令,即可以比较容易地设计一个命令队列和宏命令。一般说来,组合命令是Composite模式的一个实例。
4.增加新的Command很容易,因为这无需改变已有的类。
5.可以方便地实现对请求的Undo和Redo。

缺点:

使用命令模式可能会导致某些系统有过多的具体命令类。因为针对每一个命令都需要设计一个具体命令类,因此某些系统可能需要大量具体命令类,这将影响命令模式的使用。

更多用途:

1.宏命令模式:命令模式 加 组合模式,我们可以将多个命令组合到一起来实现命令的批处理。
2.队列请求:将命令排成一个队列打包,一个个调用 execute 方法,如线程池的任务队列,线程不关心任务队列中是读 IO 还是计算,只取出命令后执行,接着进行下一个。
3.日志请求:某些应用需要我们将所有的动作记录在日志中,然后在系统死机等情况出现时,重新调用这些动作恢复到之前的状态。如数据库事务。

参考资料:

  1. Head First Design Patterns
  2. 老师上课的PPT
  3. https://blog.csdn.net/wwh578867817/article/details/51533263
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值