基本介绍

命令模式(Command Pattern)是对命令的封装,每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行操作。命令模式解耦了请求方和接收方,请求方只需请求执行命令,不用关心命令是怎样被接收,怎样被操作以及是否被执行.….等。命令模式属于行为型模式。

命令模式类图

在这里插入图片描述
从类图中我们可以看到命令模式主要包含四个角色:

  1. 接收者角色(Receiver):该类负责具体实施或执行一个请求
  2. 命令角色(Command):定义需要执行的所有命令行为;
  3. 具体命令角色( ConcreteCommand)该类内部维护一个接收者(Receiver)在其 execute()方法中调用 Receiver 的相关方法
  4. 请求者角色(Invoker):接收客户端的命令,并执行命令

命令模式案例举例

假如我们自己开发一个播放器,播放器有播放功能、有拖动进度条功能、停止播放功能、暂停功能,我们自己去操作播放器的时候并不是直接调用播放器的方法,而是通过一个控制条去传达指令给播放器内核,那么具体传达什么指令,会被封装为一个一个的按钮。那么每个按钮的就相当于是对一条命令的封装。用控制条实现了用户发送指令与播放器内核接收指令的解耦。

看代码:


/**
 * 创建播放器内核
 */
public class GPlayer {
    public void play(){
        System.out.println("正常播放");
    }


    public void speed(){
        System.out.println("拖动进度条");
    }

    public void stop(){
        System.out.println("停止播放");
    }

    public void pause(){
        System.out.println("暂停播放");
    }
}


/**
 * 命令接口
 */
public interface IAction {
    void execute();
}

/**
 * 播放指令
 */
public class PlayAction implements IAction{

    private GPlayer gPlayer;

    public PlayAction(GPlayer gPlayer) {
        this.gPlayer = gPlayer;
    }

    @Override
    public void execute() {
        gPlayer.play();
    }
}

/**
 * 拖动进度条指令
 */
public class SpeedAction implements IAction{

    private GPlayer gPlayer;

    public SpeedAction(GPlayer gPlayer) {
        this.gPlayer = gPlayer;
    }

    @Override
    public void execute() {
        gPlayer.speed();
    }
}


/**
 * 暂停指令
 */
public class PauseAction implements IAction{

    private GPlayer gPlayer;

    public PauseAction(GPlayer gPlayer) {
        this.gPlayer = gPlayer;
    }

    @Override
    public void execute() {
        gPlayer.pause();
    }
}


/**
 * 拖动进度条指令
 */
public class StopAction implements IAction{

    private GPlayer gPlayer;

    public StopAction(GPlayer gPlayer) {
        this.gPlayer = gPlayer;
    }

    @Override
    public void execute() {
        gPlayer.stop();
    }
}


/**
 * 创建控制条
 */
public class Controller {
    private List<IAction> iActions = new ArrayList<>();

    public void addAction(IAction iAction){
        iActions.add(iAction);
    }

    public void execute(IAction iAction){
        iAction.execute();
    }

    public void executes(){
        for (IAction iAction : iActions) {
            iAction.execute();

        }
        iActions.clear();
    }
}


public class Client {
    public static void main(String[] args) {
        GPlayer gPlayer = new GPlayer();
        Controller controller = new Controller();
        controller.execute(new PauseAction(new GPlayer()));

        System.out.println("----------------");

        controller.addAction(new PlayAction(gPlayer));
        controller.addAction(new PauseAction(gPlayer));
        controller.addAction(new SpeedAction(gPlayer));
        controller.addAction(new StopAction(gPlayer));

        controller.executes();
    }
}


运行结果:

暂停播放
----------------
正常播放
暂停播放
拖动进度条
停止播放

由于控制条已经与播放器内核解耦了,以后如果想扩展新命令,只需增加命令即可,控制条的结构无需改动。

命令模式在源码中的体现

  1. JDK中的Runnable接口,就是一个命令的抽象,实际上调用线程的start方法之后,线程就会去抢CPU资源,抢到资源后才会执行run()方法。所以Runnable接口把用户请求和CPU执行进行了解耦
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐