设计模式之七——命令模式(Command)

正式定义

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

实例讲解

让我们通过一个演示例子来对命令模式有一个直观的了解。
假设我们要设计一个遥控器,这个遥控器具有一个可编程的插槽,插槽有对应的开关按钮,并且还有一个整体的撤销按钮。假设我们现在要用这个遥控器来控制车库门,车库门类如下所示:

    package com.star.command;

/**
 * 车库门类,它具有开启、关闭、开灯、关灯等功能
 */
public class GarageDoor {
    public void up(){ System.out.println("Garage Door up");}
    public void down(){ System.out.println("Garage Door down"); }
    public void stop(){ System.out.println("Garage Door stop"); }
    public void lightOn(){ System.out.println("Garage Door LightOn");}
    public void lightOff(){ System.out.println("Garage Door LightOff");}
}

车库门是接受命令的对象,我们称它为命令的接收者。接下来我们创建一个车库门打开的命令类,这个对象接受一个车库门对象,调用它的up方法来打开车库门,同时调用lightOn方法打开车库的灯。

package com.star.command;

/**
 * 车库门打开命令。
 * 是一个Command。
 * @see Command
 * 接收一个车库门对象,并调用其功能方法来实现自己的execute方法
 */
public class GarageDoorOpenCommand implements Command {
    GarageDoor garageDoor;

    public GarageDoorOpenCommand(GarageDoor garageDoor) {
        this.garageDoor = garageDoor;
    }

    public void execute() {
        garageDoor.up();
        garageDoor.lightOn();

    }
}

GarageDoorOpenCommand是一个具体的命令,同时我们注意到GarageDoorOpenCommand实现了Command接口,Command接口内容如下:

package com.star.command;
/**
 * 命令接口。
 * 定义了统一的execute()方法,所有的命令类都需要继承该接口
 */
public interface Command {
    public void execute();
}

Command接口是一个抽象的命令,这个接口只有一个execute方法。让车库门打开命令实现一个命令接口是有好处的,这样可以让命令的调用者与命令的接收者——车库门类解耦,以后我们需要增加新的命令的时候,比如说添加一个卧室灯控的命令,那么只需要让这个命令实现Command接口,而不需要修改命令调用者的代码,这体现了“对拓展开放,对修改关闭”的OO设计原则。
现在我们有了车库门、车库门打开命令,现在我们需要一个遥控器来操控这个命令:

package com.star.command;

/**
 * 简单遥控器类。
 * 该类可以考虑构造成单例模式,毕竟遥控器一个就够了。
 */
public class SimpleRemoteControl {
    /**
     * 使用command接口,来实现调用者与具体命令的解耦
     */
    Command command;

    //不使用构造器引入command的原因是,构造器只能在构造对象时使用一次,之后便无法更改。
    public SimpleRemoteControl() {}

    /**
     * setter方法,用于设置命令,并且后面可以再次调用该方法更改command。
     * @param command 需要执行的命令
     */
    public void setCommand(Command command) {
        this.command = command;
    }
    //模拟遥控器按下的操作,调用命令的execute方法。
    public void buttonWasPressed(){
        command.execute();
    }
}

这个遥控器持有一个命令的引用,并用setCommand()方法来设置命令。当遥控器被按下,即buttonWasPressed()方法执行时,遥控器会调用传进来的命令的execute方法完成功能操作。所以遥控器是命令的调用者
现在,让我们来测试一下我们的遥控器是否起作用:

    package com.star.command;

/**
 * 遥控器测试类
 * 在命令模式中担当“客户”这一角色,负责创建命令,并将一个接收者传入命令中。
 */
public class RemoteControlTest {  //客户
    public static void main(String[] args) {
        //创建遥控器
        SimpleRemoteControl remoteControl=new SimpleRemoteControl(); //调用者
        //创建一个车库门对象,也就是命令的接收者
        GarageDoor garageDoor=new GarageDoor();  //接收者
        //创建车库门打开命令,传入一个车库门对象
        GarageDoorOpenCommand command=new GarageDoorOpenCommand(garageDoor); //命令
        //为遥控器设置命令——把命令传给调用者。
        remoteControl.setCommand(command);
        //按下遥控器
        remoteControl.buttonWasPressed();

    }
}
 /* 输出为:
        Garage Door up
        Garage Door LightOn

        Process finished with exit code 0
  */

在测试类中,我们首先创建了一个调用者,也就是遥控器。接着我们创建了车库门对象和车库门打开命令对象,他们分别是接收者命令。我们将接收者传递进了命令中,以便在调用者调用命令时执行具体的操作。然后我们使用setCommand()方法将命令传递给了遥控器,最后,按下遥控器的按钮。从输出中我们可以看到,当我们按下按钮的时候,车库门打开了,车库灯也打开了。RemoteControlTest类创建了命令和接收者,并将接收者传入到命令当中。我们称它为客户

模式总结

从上面的例子我们可以看到,我们用一个“打开车库门命令”加载按钮插槽,同样我们可以用setCommand()命令加载另一个命令,如“打开卧室灯命令”。遥控器插槽根本不在乎所拥有的的是什么命令,只要该命令对象实现了Command接口就可以了。
命令模式的类图:
leitu
命令模式将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。

完整的实例已经上传到Github,欢迎大家克隆学习。Github项目地址:https://github.com/Dodozhou/DesignPatternLearning

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值