努力保头发的打工人
努力保头发的打工人
发布于 2020-12-31 / 17 阅读 / 0 评论 / 0 点赞

命令模式

1.概述

命令模式是一个高内聚的模式,其定义为:将一个请求封装成一个对象,从而让你使用不同的请求吧客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

命令模式通用类图如下:

命令模式类图.png

  • Receiver 接收者,就是干活的角色,命令传递到这里应该被执行的。

  • Command 命令角色,需要执行的命令都在这里声明。

  • Invoker 调用者角色,接收到命令并执行命令。

2.优缺点

2.1 优点
  • 类间解耦 调用者和接收者之间没有任何依赖关系,调用者只需调用Command抽象类的execute方法,不需要了解是那个接收者。

  • 可拓展性 Command的子类可以非常容易的扩展。

  • 结合其他模式更优秀 结合责任链模式实现命令族解析任务;结合模板方法模式可以减少Command子类的膨胀问题。

2.2 缺点

命令越多,Command的子类就越多,使用时需要慎重考虑。

3.实践案例

通用类图中client还需了解到都有哪些具体执行者才能发布命令(指定谁去执行那个命令),也可以只指定去执行那个命令,具体要谁执行,可以在命令类里面规定。进一步减少类间的耦合,下面案例按照后者写代码。

创建调用者类,@setter即是set方法

/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 命令调用者
 */
@Setter
public class Invoker {
​
    // 需要知道要执行什么命令
    private CommandAbstract command;
​
    /**
     * 执行高层命令,调用具体的命令
     */
    public void action(){
        command.execute();
    }
}

创建命令抽象类和具体命令类

/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 命令抽象类
 */
public abstract class CommandAbstract {
​
    protected final ReceiverAbstract receiverAbstract;
​
    // 实现类必须都定义一个接受者(如果命令复杂可以改为集合类型)
    public CommandAbstract(ReceiverAbstract receiver){
        this.receiverAbstract = receiver;
    }
​
    // 每个命令类都必须有一个执行命令的方法
    public abstract void execute();
}
​
/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 具体的命令1
 */
public class Command1 extends CommandAbstract{
​
    public Command1(){
        super(new Receiver1());
    }
​
    @Override
    public void execute() {
        // 这个命令的业务逻辑
        super.receiverAbstract.doSomething();
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 命令2
 */
public class Command2 extends CommandAbstract{
​
    public Command2(){
        super(new Receiver2());
    }
​
    @Override
    public void execute() {
        super.receiverAbstract.doSomething();
    }
}

创建接收者抽象类和具体接收者,也就是实际执行命令的角色

/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 接收者抽象类
 */
public abstract class ReceiverAbstract {
​
    // 接受者必须做点什么
    public abstract void doSomething();
}
​
/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 命令接收者, 具体的执行者
 */
public class Receiver1 extends ReceiverAbstract{
​
    @Override
    public void doSomething() {
        System.out.println("执行者1做点什么...");
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe 命令接受者
 */
public class Receiver2 extends ReceiverAbstract{
​
    @Override
    public void doSomething() {
        System.out.println("执行者2做点什么...");
    }
}

在测试类中向调用者发布命令

/**
 * @author chiangtaol
 * @date 2020-12-03
 * @describe
 */
class InvokerTest {
​
    @Test
    void action() {
        Invoker invoker = new Invoker();
        // 高层模块指定调用者执行一个命令1
        invoker.setCommand(new Command1());
        invoker.action();
​
        // 高层模块指定调用者执行一个命令2
        invoker.setCommand(new Command2());
        invoker.action();
    }
}

运行结果如下:

执行者1做点什么... 执行者2做点什么...

高层模块不需要知道谁具体执行,只要告诉调用者执行那个命令即可。