命令模式

行为型模式

命令模式(Command Pattern)是一种数据驱动的设计模式,请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

介绍

意图: 将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。

主要解决: 在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。

何时使用: 在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

如何解决: 通过调用者调用接受者执行命令,顺序:调用者→接受者→命令。

关键代码: 定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

具体实现

命令模式

我们买了一套智能家电,有照明灯,风扇,冰箱,电视等等,我们只要在手机上安装app就可以控制这些家电,但我们不想针对每一种家电都安装一个app来分别控制,我们希望一个app就可以控制全部的家电。

在该案例中我们采用遥控器形式来展现命令模式。

遥控器

第一步:创建命令接口

public interface Command {

    //执行命令
    void execute();

    //撤销命令
    void undo();
}

第二步:创建电灯和电视机命令执行对象

public class LightReceiver {

    public void on(){
        System.out.println("电灯打开了...");
    }

    public void off(){
        System.out.println("电灯关闭了...");
    }
}
public class TVReceiver {

    public void on() {
        System.out.println("电视机打开了...");
    }

    public void off() {
        System.out.println("电视机关闭了...");
    }
}

第三步:创建电灯和电视机操作实现类

public class LightOnCommand implements Command {

    //聚合LightReceiver
    private LightReceiver lightReceiver;

    public LightOnCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        System.out.println("调用接受者的方法...");
        lightReceiver.on();
    }

    @Override
    public void undo() {
        System.out.println("调用接受者的方法...");
        lightReceiver.off();
    }
}
public class LightOffCommand implements Command {

    //聚合LightReceiver
    private LightReceiver lightReceiver;

    public LightOffCommand(LightReceiver lightReceiver) {
        this.lightReceiver = lightReceiver;
    }

    @Override
    public void execute() {
        System.out.println("调用接受者的方法...");
        lightReceiver.off();
    }

    @Override
    public void undo() {
        System.out.println("调用接受者的方法...");
        lightReceiver.on();
    }
}
public class TVOffCommand implements Command {

    //聚合TVReceiver
    private TVReceiver tvReceiver;

    public TVOffCommand(TVReceiver tvReceiver) {
        this.tvReceiver = tvReceiver;
    }

    @Override
    public void execute() {
        System.out.println("调用接受者的方法...");
        tvReceiver.off();
    }

    @Override
    public void undo() {
        System.out.println("调用接受者的方法...");
        tvReceiver.on();
    }
}
public class TVOnCommand implements Command {

    //聚合TV
    private TVReceiver tvReceiver;

    public TVOnCommand(TVReceiver tvReceiver) {
        this.tvReceiver = tvReceiver;
    }

    @Override
    public void execute() {
        System.out.println("调用接受者的方法...");
        tvReceiver.on();
    }

    @Override
    public void undo() {
        System.out.println("调用接受者的方法...");
        tvReceiver.off();
    }
}
/**
 * 没有任何命令,即空执行:用于初始化每个按钮,当调用空命令时,对象什么都不做
 */
public class EmptyCommand implements Command{


    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}

第四步:创建遥控器

public class RemoteController {

    //开关命令数组
    Command[] onCommands;
    Command[] offCommands;

    //执行撤销命令
    Command undoCommand;

    public RemoteController() {
        onCommands = new Command[5];
        offCommands = new Command[5];

        for (int i = 0; i < 5; i++) {
            onCommands[i] = new EmptyCommand();
            offCommands[i] = new EmptyCommand();
        }
    }

    //给我们的按钮设置你需要的命令
    public void setCommand(int no, Command onCommand, Command offCommand) {
        onCommands[no] = onCommand;
        offCommands[no] = offCommand;
    }

    //按下开按钮
    public void onButtonWasPushed(int no) {
        //找到你按下的开的按钮,并调用对应方法.
        onCommands[no].execute();
        //记录当前按钮,用于撤销.
        undoCommand = onCommands[no];
    }

    //按下关按钮
    public void offButtonWasPushed(int no) {
        //找到你按下的关的按钮,并调用对应方法.
        offCommands[no].execute();
        //记录当前按钮,用于撤销.
        undoCommand = offCommands[no];
    }

    //按下撤销按钮
    public void undoButtonWasPushed(int no) {
        undoCommand.undo();

    }

}

第五步:创建测试类

public class Client {

    public static void main(String[] args) {
        //使用命令设计模式,完成通过遥控器,对电灯的操作

        //创建电灯对象(接受者)
        LightReceiver lightReceiver = new LightReceiver();
        //创建电灯相关的开关命令
        LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
        LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
        //需要一个遥控器来控制
        RemoteController remoteController = new RemoteController();
        //给我们的遥控器设置命令,比如 no = 0 是电灯的开和关操作.
        remoteController.setCommand(0, lightOnCommand, lightOffCommand);
        System.out.println("---------按下电灯的开按钮--------");
        remoteController.onButtonWasPushed(0);
        System.out.println("---------按下电灯的关按钮--------");
        remoteController.offButtonWasPushed(0);
        System.out.println("---------按下电灯的撤销按钮--------");
        remoteController.undoButtonWasPushed(0);

        //创建电视机对象(接受者)
        TVReceiver tvReceiver = new TVReceiver();
        //创建电视机相关的开关命令
        TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
        TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
        //需要一个遥控器来控制
        //给我们的遥控器设置命令,比如 no = 1 是电视机的开和关操作.
        remoteController.setCommand(1, tvOnCommand, tvOffCommand);
        System.out.println("---------按下电视机的开按钮--------");
        remoteController.onButtonWasPushed(1);
        System.out.println("---------按下电视机的关按钮--------");
        remoteController.offButtonWasPushed(1);
        System.out.println("---------按下电视机的撤销按钮--------");
        remoteController.undoButtonWasPushed(1);
    }

}

运行如下:

---------按下电灯的开按钮--------
调用接受者的方法...
电灯打开了...
---------按下电灯的关按钮--------
调用接受者的方法...
电灯关闭了...
---------按下电灯的撤销按钮--------
调用接受者的方法...
电灯打开了...
---------按下电视机的开按钮--------
调用接受者的方法...
电视机打开了...
---------按下电视机的关按钮--------
调用接受者的方法...
电视机关闭了...
---------按下电视机的撤销按钮--------
调用接受者的方法...
电视机打开了...

优点:

    1、降低了系统耦合度。 2、新的命令可以很容易添加到系统中去。

缺点:

    使用命令模式可能会导致某些系统有过多的具体命令类。


神秘杰克
768 声望392 粉丝

Be a good developer.