《一天一模式》— 命令模式

原创
2020/05/29 23:27
阅读数 206

一、命令模式的概念

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

二、什么时候使用命令模式

调用者与实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。 我通常这么理解命令模式,某些业务场景,一族对象会有一组命令,以命令的角度为主定义命令对象(有执行和撤回两种操作),然后把执行的过程委托给对象。

什么是一族对象?举个例子,就是奔驰汽车、宝马汽车、奥迪汽车等。

什么是一组命令?举个例子,就是远程控制汽车时的开门命令、开空调命令、开天窗命令等。

这种情况就可以使用命令模式。使用命令模式有降低耦合、可扩展、可读性高、使用方便(可撤回)等等的好处。

具体我们来看一下,如何用Java代码实现命令模式。

三、怎么使用命令模式

3.1 实现方式

还是以上面的需求为例子,使用命令模式对上面的业务进行实现,下面是类图和代码:

代码如下:

// 车辆抽象类
public abstract class Vehicle {

    abstract void openDoor();

    abstract void openWindow();

}

public class Audi extends Vehicle {

    void openDoor() {
        System.out.println("奥迪:开门。");
    }

    void openWindow() {
        System.out.println("奥迪:开窗。");
    }

}

public class Benz extends Vehicle {

    void openDoor() {
        System.out.println("奔驰:开门。");
    }

    void openWindow() {
        System.out.println("奔驰:开窗。");
    }

}

// 命令模式接口
public interface Command {

    void execute();

}

// 开门命令
public class OpenDoorCommand implements Command {

    private Vehicle vehicle;

    public OpenDoorCommand(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    public void execute() {
        vehicle.openDoor();
    }

}

// 开窗命令
public class OpenWindowCommand implements Command {

    private Vehicle vehicle;

    public OpenWindowCommand(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    public void execute() {
        vehicle.openWindow();
    }

}

public class Client {

    public static void main(String[] args) {
        // 创建开门命令
        Command openDoorCommand = new OpenDoorCommand(new Benz());
        // 创建开窗命令
        Command openWindowCommand = new OpenWindowCommand(new Audi());
        // 执行2个命令
        openDoorCommand.execute();
        openWindowCommand.execute();
    }

}

//输出:
//奔驰:开门。
//奥迪:开窗。

3.2 命令模式的好处

使用命令的模式的好处如下:

  • 可读性高:从语义上可直接阅读到动作,对外提供了统一的表现;
  • 拓展性高:可以很方便地添加新的命令,也可以控制命令的撤回或重复执行;
  • 耦合性低:解除了调用者与具体实现的耦合, 屏蔽了底层的复杂实现;

3.3 注意事项

功能足够简单。如果功能本身比较简单,则不建议引入命令模式,它会带来更多的复杂性,以及更高的开发成本。

命令的意义不清晰或经常变化时,则不太适合使用命令模式。

一般来说,尽量设计傻瓜式命令,它只懂得调用一个接收者的一个行为(单一职责)。

四、总结

如何实现撤销命令,是一直值得讨论的问题,面相扩展性来说,可以遵循一个设计方式:

不要只是记录最后一个命令,而使用一个堆栈(后进先出)记录操作过的每一个命令。然后,不管什么时候执行撤销,你都可以从堆栈中取出最上层的命令,然后执行undo()方法来撤销它。

最后说一些其他的,命令模式还可以有更多的用途,比如使用在队列请求和日志请求。

想象一下,有一个工作队列(先进先出),你在某一端添加命令,然后另一端则是线程,线程从队列中取出一个命令,然后调用它的execute()方法,等待这个调用完成,然后丢弃该命令,执行下一个……

在想象一下,某些应用需要我们将所有的动作都记录在日志中,并能在系统死机后,重新调用这些动作恢复到之前的状态。我们可以在执行命令的时候,将历史记录存储在磁盘中。一旦系统死机重启后,我们就可以将命令对象读取出来重新执行execute()方法。

以上就是我对命令模式的一些理解,有不足之处请大家指出,谢谢。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部