java设计模式之命令模式

命令模式的定义:

  命令模式是对命令的封装,每个命令都是一个操做:请求方发出请求要求执行一个操做;接收方收到请求,并执行操做。命令模式解耦了请求方shell

和接收方,请求方只需请求执行命令,不用关心命令怎么被接收、怎样操做以及是否被执行等。命令模式属于行为型设计模式。设计模式

  在软件系统中,行为请求者与行为实现者一般是一种紧耦合关系,由于这样的实现简单明了。但紧耦合关系缺少扩展性,在某些场合中,须要对行为架构

进行记录、撤销或者重作等处理时,只能修改源码。而命令模式经过在请求与实现之间引入一个抽象命令接口。解耦了请求与实现,而且中间件是抽象的,测试

它由不一样的子类实现,所以具备扩展性。因此,命令模式的本质是解耦命令请求与处理。this

命令模式的应用场景:

  • 现实语义中具有“命令”的操做(如命令菜单、shell命令等)。
  • 请求的调用者和接收者须要解耦,使得调用者和接收者不之间交互。
  • 须要抽象除等待执行的行为,好比撤销操做和恢复等操做。
  • 须要支持命令宏(即命令组合操做)。

命令模式的UML类图:

 

 

 

 

 从上图能够看出,命令模式主要包含4个角色。spa

  • 接收者角色(Receiver):该类负责具体实施或执行一个请求。
  • 命令模式(ICommand):定义须要执行的全部命令行为。
  • 具体命令角色(ConcreteCommand):该类内部维护一个Receiver在其execute()方法中调用Receiver的相关方法。
  • 请求者角色(Invoker):接收客户端的命令,并执行命令。

  从命令模式的UML类图中,能够很清晰地看出,ICommand的出现就是做为Receiver和Invoker的中间件,解耦了彼此。命令行

使用命令模式重构播放器控制条:

  假如咱们开发一个播放器,播放器播放功能、拖动进度条功能、中止播放功能、暂停功能,咱们在操做播发器的时候并不知道之间调用播放器设计

哪一个功能,而是经过一个控制传达去传递指令给播放器内核,具体传达什么指令,会被封装成一个个按钮。那么每一个按钮就至关于一条命令的封装。日志

用控制条实现了用户发送指令与播放器内核接收指令的解耦。下面来看代码,首先建立播放器内核类:code

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;
    }

    public void execute() {
        gplayer.play();
    }
}

建立暂停指令类:

public class PauseAction implements IAction {
    private GPlayer gplayer;

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

    public void execute() {
        gplayer.pause();
    }
}

建立拖动进度条类:

public class SpeedAction implements IAction {
    private GPlayer gplayer;

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

    public void execute() {
        gplayer.speed();
    }
}

建立中止播放指令:

public class StopAction implements IAction {
    private GPlayer gplayer;

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

    public void execute() {
        gplayer.stop();
    }
}

建立控制条controller类:

public class Controller {
    private List<IAction> actions = new ArrayList<IAction>();

    public void addAction(IAction action) {
        actions.add(action);
    }

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

    public void executes() {
        for (IAction action : actions) {
            action.execute();
        }
        actions.clear();
    }
}

从上面代码来看,控制条能够执行单条命令,也能够批量执行多条命令。下面看客户端的测试代码:

public class Test {
    public static void main(String[] args) {

        GPlayer player = new GPlayer();
        Controller controller = new Controller();
        controller.execute(new PlayAction(player));

        controller.addAction(new PauseAction(player));
        controller.addAction(new PlayAction(player));
        controller.addAction(new StopAction(player));
        controller.addAction(new SpeedAction(player));
        controller.executes();
    }
}

因为控制条已经与播放器内核解耦了,之后若是想扩展新命令,只须要增长命令便可,控制条的结构无须改动。

命令模式的优势:

  • 经过引入中间件(抽象接口),解耦了命令请求与实现。
  • 扩展性良好,能够很容易地增长新命令。
  • 支持组合命令,支持命令队列。
  • 能够在现有命令的基础上,增长额外功能,好比日志记录,结合装饰器模式会更加灵活。

命令模式的缺点:

  • 具体命令类可能过多。
  • 命令模式的结果其实就是接收方的执行结果,可是为了以命令的形式进行架构、解耦请求与实现,引入额外类型结构(引入请求方与抽象命令接口)。
  • 增长了理解上的困难。不过这也是设计模式的通病抽象必然会额外增长类的数量;代码抽离确定比代码聚合更难理解。
相关文章
相关标签/搜索