zoukankan      html  css  js  c++  java
  • Java设计模式----命令模式

    假如公司计划开发一套MDM(移动设备管理)系统,即管理员可以在web页面上操控接入系统的手机(这里不区分Android和iOS),比如,针对某台手机,在web页面上点击“锁屏”按钮,该手机就锁屏了,点击“解锁”按钮,该手机就解锁了。

    对于这套系统,核心部分无疑就是刚刚描述的一系列对手机下发命令。这套系统可以有许多不同的命令,锁屏和解锁只是其中的个例,那么有那么多的命令,实际应用中又设计到同时操控多台设备,在很短的时间内可能会产生许多命令,如果系统设计不当,很可能时效性就会收到影响,所以上面管理员类依赖于手机操控类,即命令(请求)的发送者与命令(请求)的执行者耦合这种简单的设计模式会有很大问题。

    既然要管理许多命令,我们自然相当用list或者queue保存命令,基于某种策略执行命令,比如可以设置命令的优先级等等,这样,就自然需要一个负责命令调度的角色, 通过这个中间角色,来执行对手机的操控命令。通常这个中间角色叫做: invoker, 引入了invoker, 我们就需要重新设计一下这个系统,目标是解耦命令发送者和命令执行者,同时满足命令的可扩展性,保证整个系统的健壮性。命令模式,就是可以满足以上需求的设计模式。


    1.命令模式

    命令模式(Command);将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化,对请求排队或者对请求做日志记录,以及可以支持撤销的操作。 ----《大话设计模式》

    我们使用命令模式来重新设计这套系统的核心部分:

    命令模式把具体的命令(请求)封装为对象LockScreenCommand(锁屏命令)和UnlockScreenCommand(解锁命令), 锁屏和解锁一台手机,流程如下:

    1. Admin(管理员)创建锁屏命令LockScreenSommand对象和解锁屏命令对象UnlockScreenCommand;
    2. 管理员将这两个命令对象,给Invoker, Invoker将这两条命令放入列表中;
    3. 可以设置监听或者定时任务取激活Invoker取执行命令,但是我这里就简单在Admin中调用Invoker对象的inform()方法;
    4. Invoker的inform()方法中遍历命令,依次调用命令execute()方法执行;
    5. 命令的execute()调用MobileOperator(手机操控者)对象的action()方法,统一下发命令;
    6. 结束。

    3.代码实现

    定义抽象命令类, 也可以根据情况定义为interface。

    /**
    * 抽象命令类, 定义了执行命令的抽象方法。
    * 关联于MobileOperator,进行命令的统一下发。
    */
    abstract class Command {
    protected MobileOperator operator;
    public Command(MobileOperator operator){
    this.operator = operator;
    }
    public abstract void execute();
    }

    定义命令下发类,该类被命令类所关联。

    /**
    * 进行命令统一下发的类
    */
    class MobileOperator {
    public void action(String commandName){
    System.out.printf("下发【%s】命令 ",commandName);
    }
    }

    然后定义两个具体的命令类,实现对手机的命令(请求)的封装。

    /**
    * 锁屏命令
    */
    class LockScreenCommand extends Command {

    public LockScreenCommand(MobileOperator operator) {
    super(operator);
    }

    @Override
    public void execute() {
    operator.action("锁屏");
    }

    }
    /**
    * 解锁命令
    */
    class UnlockScreenCommand extends Command {

    public UnlockScreenCommand(MobileOperator operator) {
    super(operator);
    }

    @Override
    public void execute() {
    operator.action("解锁");
    }
    }

    定义Invoker, 这个类很关键,不仅解耦了请求者(Admin)和命令执行者(MobileOperator),还可以对命令的执行进行管理调度,可以扩展,现在只定义了增加命令方法。如果有需求,还可以撤销命令、调整命令顺序等等......

    /**
    * 命令调度
    */
    class Invoker {
    //这里姑且用ArrayList
    List<Command> commandList = new ArrayList<>();

    //添加命令
    public void setCommand(Command command) {
    commandList.add(command);
    }

    public void inform(){
    for (Command command : commandList) {
    command.execute();
    }
    }
    }

    定义命令(请求)的发送者---Admin, 作为入口执行命令

    public class Admin {
        public static void main(String[] args) {
            // 手机操控对象
            MobileOperator operator = new MobileOperator();
            // 创建命令
            Command lockCommand = new LockScreenCommand(operator);
            Command unLockCommand = new UnlockScreenCommand(operator);
            //添加命令
            Invoker invoker = new Invoker();
            invoker.setCommand(lockCommand);
            invoker.setCommand(unLockCommand);
    
            //执行命令
            invoker.inform();
        }
    }

    输出结果:

    下发【锁屏】命令
    下发【解锁】命令

     

    以上代码采用命令模式,实现了对手机下发命令,解耦了命令的发送者和执行者。


    5.总结

    通过一个场景:移动设备管理系统,应用命令模式对手机下发命令。通过上面的例子可以体会出命令模式,就是把命令(请求)封装成对象, 请求者任意生成若干个命令对象,把这些对象交给Invoker来管理,在实际项目中,通常请求者的工作到此就完成了,执行命令不需要请求者关系,通常由Invoker来进行调度,而本例为了简便,故在请求者Admin的main方法中调用了invoker.infom()。由于有Invoker这样一个“中间角色”的加入,系统的耦合度就降下来了,比如,我们可以扩展其它各种命令而不需要顾及到Admin,同时,还可以扩展Invoker的功能,实现命令按照自己需要的策略来执行,真实一石二鸟。

    命令模式就是一把解决请求-执行这类模式的好工具,不过再好的工具也有其局限性,比如,常用的控制手机的命令也许只有十来种。倘若其它命令,有成百上千种,那么就要慎重使用命令模式了,光是实现这些命令就把人累死了,所以,当命令种类过多时,不适宜使用命令模式。

  • 相关阅读:
    UVA 562 Dividing coins
    who is in front of me 解题报告
    UVA 111 历史考试
    UVA 1045 最长公共子序列
    HDU 1003 解题报告
    ACM2014-04训练计划
    基于邻接表的新顶点的增加
    4004.六度空间理论
    4003.基于Dijsktra算法的最短路径求解
    4002.基于快排思想的查找
  • 原文地址:https://www.cnblogs.com/yxlaisj/p/10370809.html
Copyright © 2011-2022 走看看