reupe

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

假如公司计划开发一套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】命令\n",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的功能,实现命令按照自己需要的策略来执行,真实一石二鸟。

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

 

posted on 2019-02-13 20:01  yxlaisj  阅读(164)  评论(0编辑  收藏  举报