Command Patterns

GoF定义:将请求作为一个对象来处理。使得可以使用不同的请求、队列或者日志请求来参数化客户端。并且支持撤销操作。

概念

通常,四个概念是相互关联的

  1. command object:在接收端可以调用某个特定的方法,它保存着可以调用receiver方法的参数
  2. invoker:只知道命令接口(接收符合Command接口声明的对象),不知道具体哪个命令被调用
  3. client:持有invoker对象和command对象,客户端决定哪些命令在一个特定的时间点执行,要实现这个功能,客户端要将command对象传给invoker对象
  4. receiver:命令的具体操作定义在这里

例子

现实世界:我们不能改变过去发生的事情,但是我们希望原来可以那样做,可惜没有时光机的存在。但是日常生活中,我们可以不做或者重做很多事情,例如橡皮可以擦掉画的画,重新设计客厅。所以,取消和重做的操作是我们生活的一部分,我们通过一些内在或外在的命令来实现它们
代码世界:微软的Paint软件,我们通过工具栏可以随时undo/redo很多操作

展示

代码

public class CommandPatternEx
{
    public static void main(String[] args)
    {
        System.out.println("***Command Pattern Demo***\n");
        Receiver intendedreceiver=new Receiver();
        /*Client holds Invoker and Command Objects*/
        Invoker inv = new Invoker();
        MyUndoCommand unCmd = new MyUndoCommand(intendedreceiver);
        MyRedoCommand reCmd = new MyRedoCommand(intendedreceiver);
        inv.executeCommand(unCmd);
        inv.executeCommand(reCmd);
    }
}

interface ICommand
{
    void doSomething();
}

class MyUndoCommand implements ICommand
{
    private Receiver receiver;

    public MyUndoCommand(Receiver receiver)
    {
        this.receiver = receiver;
    }

    @Override
    public void doSomething()
    {
        receiver.performUndoCommand();
    }
}

class MyRedoCommand implements ICommand
{
    private Receiver receiver;

    public MyRedoCommand(Receiver receiver)
    {
        this.receiver = receiver;
    }

    @Override
    public void doSomething()
    {
        receiver.performRedoCommand();
    }
}

class Receiver
{
    public void performUndoCommand()
    {
        System.out.println("Execution--Undo");
    }

    public void performRedoCommand()
    {
        System.out.println("Execution--Redo");
    }
}

class Invoker
{
    ICommand cmd;

    public void executeCommand(ICommand cmd)
    {
        this.cmd = cmd;
        this.cmd.doSomething();
    }
}

Note

  1. 这个模式广泛应用于undo/redo操作
  2. 回调函数可以用这个模式设计(如果没有函数式接口,可以传入一个command对象,即在方法的不同状态下执行不同的命令)
  3. 当我们处理事务时很有用,可以响应数据的变化(结合2,当数据库数据在不同状态下执行不同命令)
  4. 命令易于扩展。它们和其它的对象没有什么不同,在使用Command对象时,不需要改变现在系统的类结构(扩展接口即可)
  5. 另一种模式叫做(chain of responsibility)这个模式中,我们将一个请求传给一系列的对象串(chain),希望这串对象中的任一个可以处理这个请求。但是在本例中,我们将请求传给了特定的对象(invoker对象)

思考

这个模式核心在于将命令和具体操作解耦,即(Command对象+Receiver对象),而Invoker对象作为统一的调命令接口防止了新建各种command对象调不同的方法。所有的command对象都是客户端组装完成(要调的命令所需的参数,且包含一个Receiver类),然后直接传入Invoker执行命令

posted on 2020-11-30 20:03  老鼠不上树  阅读(74)  评论(0)    收藏  举报