Java/Android 设计模式系列(16)--命令模式

   这篇博客我们来介绍一下命令模式(Command Pattern),它是行为型设计模式之一。命令模式相对于其他的设计模式更为灵活多变,我们接触比较多的命令模式个例无非就是程序菜单命令,如在操作系统中,我们点击关机命令,系统就会执行一系列的操作,如先是暂停处理事件,保存系统的一些配置,然后结束程序进程,最后调用内核命令关闭计算机等,对于这一系列的命令,用户不用去管,用户只需点击系统的关机按钮即可完成如上一系列的命令。而我们的命令模式其实也与之相同,将一系列的方法调用封装,用户只需调用一个方法执行,那么所有的这些被封装的方法就会被挨个执行调用。

设计模式总目录

  Java/Android 设计模式系列–目录

特点

  将一个请求封装成一个对象,从而让用户使用不同的请求把客户端参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。
  
命令模式的使用场景:

  • 需要抽象出待执行的动作,然后以参数的形式提供出来—类似于过程设计中的回调机制,而命令模式正是回调机制的一个面向对象的替代品;
  • 在不同的时刻指定、排列和执行请求,一个命令对象可以有与初始请求无关的生存期;
  • 需要支持取消操作;
  • 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一遍;
  • 需要支持事务操作;
  • 系统需要将一组操作组合在一起,即支持宏命令。

wiki 上列出的具体使用场景:

  • GUI buttons and menu items

  • Macro recording

  • Mobile Code

  • Multi-level undo

  • Networking

  • Parallel Processing

  • Progress bars

  • Thread pools

  • Transactional behavior

  • Wizards

UML类图

  我们来看看命令模式的 uml 类图:
  这里写图片描述
命令模式的角色介绍:

  • Receiver:接收者角色

  • Command :命令接口

  • ConreteCommand:具体命令角色

  • Invoker :请求者角色

  • Client:客户端角色

由此我们可以写出命令模式的通用代码:
Receiver.class 具体逻辑执行者

public class Receiver {
    public void action() {
        System.out.print("执行具体的操作");
    }
}

Command.class 抽象命令类

public interface Command {
    void execute();
}

ConcreteCommand.clas 具体命令类

public class ConcreteCommand implements Command {

    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }
}

Invoker.class 请求者

public class Invoker {

    private Command command;

    public Invoker(Command command) {
        this.command = command;
    }

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

Client 客户端

public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        Invoker invoker = new Invoker(command);
        invoker.action();
    }
}

最后也能通过 Invoker 类调用到真正的 Receiver 执行逻辑了。

示例与源码

  这就以一个简单的控制电灯亮灭和门开关的情景为例:
Light.class 和 Door.class 实际控制类

public class Light {
    public void lightOn() {
        System.out.print("light on\n");
    }

    public void lightOff() {
        System.out.print("light off\n");
    }
}
public class Door {
    public void doorOpen() {
        System.out.print("door open\n");
    }

    public void doorClose() {
        System.out.print("door close\n");
    }
}

然后是电灯的控制类:

LightOnCommand.class 和 LightOffCommand.class

public class LightOnCommand  implements Command{
    public Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.lightOn();
    }
}
public class LightOffCommand implements Command{
    public Light light;

    public LightOffCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        light.lightOff();
    }
}

门的相关控制类:

DoorOpenCommand.class 和 DoorCloseCommand.class

public class DoorOpenCommand implements Command{

    public Door door;

    public DoorOpenCommand(Door door) {
        this.door = door;
    }

    @Override
    public void execute() {
        door.doorOpen();
    }
}
public class DoorCloseCommand implements Command{

    public Door door;

    public DoorCloseCommand(Door door) {
        this.door = door;
    }

    @Override
    public void execute() {
        door.doorClose();
    }
}

然后是一个无操作默认命令类:

NoCommand.class

public class NoCommand implements Command{
    @Override
    public void execute() {
    }
}

最后是控制类:

Controller.class

public class Controller {
    private Command[] onCommands;
    private Command[] offCommands;

    public Controller() {
        onCommands = new Command[2];
        offCommands = new Command[2];

        Command noCommand = new NoCommand();
        onCommands[0] = noCommand;
        onCommands[1] = noCommand;
        offCommands[0] = noCommand;
        offCommands[1] = noCommand;
    }

    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    public void onCommand(int slot) {
        onCommands[slot].execute();
    }

    public void offCommand(int slot) {
        offCommands[slot].execute();
    }
}

测试代码

Light light = new Light();
Door door = new Door();

LightOnCommand lightOnCommand = new LightOnCommand(light);
LightOffCommand lightOffCommand = new LightOffCommand(light);

DoorOpenCommand doorOpenCommand = new DoorOpenCommand(door);
DoorCloseCommand doorCloseCommand = new DoorCloseCommand(door);

Controller controller = new Controller();
controller.setCommand(0, lightOnCommand, lightOffCommand);
controller.setCommand(1, doorOpenCommand, doorCloseCommand);

controller.onCommand(0);
controller.offCommand(0);
controller.onCommand(1);
controller.offCommand(1);

结果:
这里写图片描述
这样就实现了对 Light 和 Door 的控制了,其实这个例子只是实现了对命令模式的基本框架而已,命令模式的用处其实在于它的日志和回滚撤销功能,每次执行命令的时候都打印出相应的关键日志,或者每次执行后都将这个命令保存进列表中并且每个命令实现一个 undo 方法,以便可以进行回滚。另外,也可以构造一个 MacroCommand 宏命令类用来按次序先后执行几条相关联命令。当然可以发散的空间很多很多,感兴趣的可以自己去实现,原理都是一样的。

总结

  命令模式将发出请求的对象和执行请求的对象解耦,被解耦的两者之间通过命令对象进行沟通,调用者通过命令对象的 execute 放出请求,这会使得接收者的动作被调用,调用者可以接受命令当作参数,甚至在运行时动态地进行,命令可以支持撤销,做法是实现一个 undo 方法来回到 execute 被执行前的状态。MacroCommand 宏命令类是命令的一种简单的延伸,允许调用多个命令,宏方法也可以支持撤销。日志系统和事务系统可以用命令模式来实现。
  命令模式的优点很明显,调用者和执行者之间的解耦,更灵活的控制性,以及更好的扩展性等。缺点更明显,就是类的爆炸,大量衍生类的创建,这也是大部分设计模式的“通病”,是一个没有办法避免的问题。

源码下载

  https://github.com/Jakey-jp/Design-Patterns/tree/master/CommandPattern

引用

https://en.wikipedia.org/wiki/Command_pattern
http://blog.csdn.net/jason0539/article/details/45110355

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值