命令模式

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

示例—遥控器

新型遥控器具有七个可编程的插槽(每个都可以指定一个不同的家电装置),每个插槽都有对应的开关按钮。这个遥控器还具备一个整体的撤销按钮。这些插槽对应的是多家不同厂商的自动化装置,例如:电灯、风扇、热水器、音响设备和其他类似的可控制装置。需求是能够创建一组控制遥控器的API,让每个插槽都能够控制一个或一组装置。请注意,能够控制目前的装置和任何未来可能出现的装置,这一点是很重要的。

UML图表示

命令模式-遥控器设计

代码演示

命令接口

package Command;

public interface Command {
    void execute();
    void undo();
}

家用电器基类

package Command;

public class Appliance {

    public Appliance(){
    }

    private String name;

    public Appliance(String name){
        this.name = name;
    }

    public void action(String action){
        System.out.println((name != null ? name + " " : "") + action);
    }
}

风扇

package Command;

public class CeilingFan extends Appliance {

    public CeilingFan() {
        super();
    }

    public static final int HIGH = 3;
    public static final int MEDIUM = 2;
    public static final int LOW = 1;
    public static final int OFF = 0;
    int speed;

    public CeilingFan(String name){
       super(name);
       speed = OFF;
    }

    public void high(){
        speed = HIGH;
        // 设置高转速
        action("CeilingFan set high");
    }

    public void medium(){
        speed = MEDIUM;
        // 设置中转速
        action("CeilingFan set medium");
    }

    public void low(){
        speed = LOW;
        // 设置低转速
        action("CeilingFan set low");
    }

    public void off(){
        speed = OFF;
        // 关闭吊扇
        action("CeilingFan is off");
    }

    public int getSpeed(){
        return speed;
    }

}

风扇的各种命令子类

package Command;

public class CeilingFanHighCommand implements Command {

    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanHighCommand(CeilingFan ceilingFan){
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.high();
    }

    @Override
    public void undo() {
        switch (prevSpeed){
            case  CeilingFan.HIGH:
                ceilingFan.high();
                break;
            case CeilingFan.MEDIUM:
                ceilingFan.medium();
                break;
            case CeilingFan.LOW:
                ceilingFan.low();
                break;
            case CeilingFan.OFF:
                ceilingFan.off();
                break;
        }
    }
}


package Command;

public class CeilingFanLowCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanLowCommand(CeilingFan ceilingFan){
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.low();
    }

    @Override
    public void undo() {
        switch (prevSpeed){
            case  CeilingFan.HIGH:
                ceilingFan.high();
                break;
            case CeilingFan.MEDIUM:
                ceilingFan.medium();
                break;
            case CeilingFan.LOW:
                ceilingFan.low();
                break;
            case CeilingFan.OFF:
                ceilingFan.off();
                break;
        }
    }
}

package Command;

public class CeilingFanMediumCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanMediumCommand(CeilingFan ceilingFan){
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.medium();
    }

    @Override
    public void undo() {
        switch (prevSpeed){
            case  CeilingFan.HIGH:
                ceilingFan.high();
                break;
            case CeilingFan.MEDIUM:
                ceilingFan.medium();
                break;
            case CeilingFan.LOW:
                ceilingFan.low();
                break;
            case CeilingFan.OFF:
                ceilingFan.off();
                break;
        }
    }
}

package Command;

public class CeilingFanOffCommand implements Command {
    CeilingFan ceilingFan;
    int prevSpeed;

    public CeilingFanOffCommand(CeilingFan ceilingFan){
        this.ceilingFan = ceilingFan;
    }

    @Override
    public void execute() {
        prevSpeed = ceilingFan.getSpeed();
        ceilingFan.off();
    }

    @Override
    public void undo() {
        switch (prevSpeed){
            case  CeilingFan.HIGH:
                ceilingFan.high();
                break;
            case CeilingFan.MEDIUM:
                ceilingFan.medium();
                break;
            case CeilingFan.LOW:
                ceilingFan.low();
                break;
            case CeilingFan.OFF:
                ceilingFan.off();
                break;
        }
    }
}

车库门

package Command;

public class GarageDoor extends Appliance {

    public GarageDoor() {
        super();
    }

    public GarageDoor(String name){
        super(name);
    }

    public void up(){
        action("GarageDoor up");
    }

    public void down(){
        action("GarageDoor down");
    }

    public void stop(){
        action("GarageDoor stop");
    }

    public void lightOn(){
        action("GarageDoor's Light is on");
    }

    public void lightOff(){
        action("GarageDoor's Light is off");
    }
}

车库门的各种命令子类

package Command;

public class GarageDoorDownCommand implements Command  {

    GarageDoor garageDoor;

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

    @Override
    public void execute() {
        garageDoor.down();
    }

    @Override
    public void undo() {
        garageDoor.up();
    }
}

package Command;

public class GarageDoorOpenCommand implements Command {

    GarageDoor garageDoor;

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

    @Override
    public void execute() {
        garageDoor.up();
    }

    @Override
    public void undo() {
        garageDoor.down();
    }
}

电灯

package Command;

public class Light extends Appliance {

    public Light() {
        super();
    }

    public Light(String name){
        super(name);
    }

    public void on(){
        action("Light is on");
    }

    public void off(){
        action("Light is off");
    }
}

电灯的各种命令子类

package Command;

public class LightOffCommand  implements Command {

    Light light;

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

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

    @Override
    public void undo() {
        light.on();
    }
}

package Command;

public class LightOnCommand implements Command {

    Light light;

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

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

    @Override
    public void undo() {
        light.off();
    }
}

音响

package Command;

public class Stereo extends Appliance {

    public Stereo() {
        super();
    }

    public Stereo(String name){
        super(name);
    }

    public void on(){
        action("Stereo is on");
    }
    public void off(){
        action("Stereo is off");
    }

    public void setCd() {
        action("Stereo set CD");
    }

    public void setDvd(){
        action("Stereo set DVD");
    }

    public void setRadio(){
        action("Stereo set radio");
    }

    public void setVolume(int volume) {
        action("Stereo set volume " + volume);
    }
}

音响的各种命令子类

package Command;

public class StereoOffCommand implements Command {

    Stereo stereo;

    public StereoOffCommand(Stereo stereo){
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.off();
    }

    @Override
    public void undo() {
        stereo.on();
        stereo.setCd();
        stereo.setVolume(11);
    }
}

package Command;

public class StereoOnWithCDCommand implements Command {

    Stereo stereo;

    public StereoOnWithCDCommand(Stereo stereo){
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.on();
        stereo.setCd();
        stereo.setVolume(11);
    }

    @Override
    public void undo() {
        stereo.off();
    }
}

空命令子类

package Command;

public class NoCommand implements Command {
    @Override
    public void execute() {
        // 什么都不做
    }

    @Override
    public void undo() {
        // 什么都不做
    }
}

批量命令子类(宏命令)

package Command;

public class MacroCommand implements Command {

    Command[] commands;

    public MacroCommand(Command[] commands){
        this.commands = commands;
    }

    @Override
    public void execute() {
        for (Command command : commands){
            command.execute();
        }
    }

    @Override
    public void undo() {

    }
}

遥控器

package Command;

public class RemoteControl {
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControl(){
        onCommands = new Command[7];
        offCommands = new Command[7];

        Command noCommand = new NoCommand();
        for (int i = 0; i < 7 ; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }

        undoCommand = noCommand;
    }

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

    public void onButtonWasPushed(int slot){
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }

    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
        undoCommand = offCommands[slot];
    }

    public void undoButtonWasPushed(){
        undoCommand.undo();
    }

    @Override
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("\n---------Remote Control----------\n");
        for (int i = 0; i < onCommands.length; i++) {
            stringBuffer.append("[slot " + i +"] " + onCommands[i].getClass().getName() +
            "   " + offCommands[i].getClass().getName() + "\n");
        }
        return stringBuffer.toString();
    }
}

测试代码

package Command;

public class RemoteLoader {
    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl();

        Light livingRoomLight = new Light("Living Room");
        Light kitchenLight = new Light("Kitchen");
        GarageDoor garageDoor = new GarageDoor();
        Stereo stereo = new Stereo("Living Room");
        CeilingFan ceilingFan = new CeilingFan("Living Room");

        LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);

        LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
        LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);

        GarageDoorOpenCommand garageOpen = new GarageDoorOpenCommand(garageDoor);
        GarageDoorDownCommand garageDown = new GarageDoorDownCommand(garageDoor);

        StereoOnWithCDCommand stereoOnWithCD = new StereoOnWithCDCommand(stereo);
        StereoOffCommand stereoOff = new StereoOffCommand(stereo);

        CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
        CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);

        remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
        remoteControl.setCommand(2, garageOpen, garageDown);
        remoteControl.setCommand(3,stereoOnWithCD, stereoOff);
        remoteControl.setCommand(4,ceilingFanMedium,ceilingFanOff);
        remoteControl.setCommand(5,ceilingFanHigh, ceilingFanOff);


        System.out.println(remoteControl);

        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);

        remoteControl.onButtonWasPushed(1);
        remoteControl.offButtonWasPushed(1);

        remoteControl.onButtonWasPushed(2);
        remoteControl.offButtonWasPushed(2);

        remoteControl.onButtonWasPushed(3);
        remoteControl.offButtonWasPushed(3);

        remoteControl.onButtonWasPushed(4);
        remoteControl.offButtonWasPushed(4);

        remoteControl.onButtonWasPushed(5);
        remoteControl.offButtonWasPushed(5);

        System.out.println("~~~~~~~~~~~~~~~~~~~~~测试撤销");

        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        remoteControl.undoButtonWasPushed();
        remoteControl.offButtonWasPushed(0);
        remoteControl.onButtonWasPushed(0);
        remoteControl.undoButtonWasPushed();

        remoteControl.onButtonWasPushed(4);
        remoteControl.offButtonWasPushed(4);
        remoteControl.undoButtonWasPushed();

        remoteControl.onButtonWasPushed(5);
        remoteControl.undoButtonWasPushed();

        System.out.println("~~~~~~~~~~~~~~~~~~~~~测试宏命令");

        Command[] partyOn = {livingRoomLightOn,kitchenLightOn,garageOpen,stereoOnWithCD,ceilingFanMedium };
        Command[] partyOff = {livingRoomLightOff, kitchenLightOff, garageDown, stereoOff, ceilingFanOff};

        MacroCommand partyOnMacro = new MacroCommand(partyOn);
        MacroCommand partyOffMacro = new MacroCommand(partyOff);
        remoteControl.setCommand(6,partyOnMacro, partyOffMacro);

        System.out.println(remoteControl);
        System.out.println("-----Pushing Macro On--------");
        remoteControl.onButtonWasPushed(6);
        System.out.println("-----Pushing Macro Of--------");
        remoteControl.offButtonWasPushed(6);
    }
}

测试结果

---------Remote Control----------
[slot 0] Command.LightOnCommand   Command.LightOffCommand
[slot 1] Command.LightOnCommand   Command.LightOffCommand
[slot 2] Command.GarageDoorOpenCommand   Command.GarageDoorDownCommand
[slot 3] Command.StereoOnWithCDCommand   Command.StereoOffCommand
[slot 4] Command.CeilingFanMediumCommand   Command.CeilingFanOffCommand
[slot 5] Command.CeilingFanHighCommand   Command.CeilingFanOffCommand
[slot 6] Command.NoCommand   Command.NoCommand

Living Room Light is on
Living Room Light is off
Kitchen Light is on
Kitchen Light is off
GarageDoor up
GarageDoor down
Living Room Stereo is on
Living Room Stereo set CD
Living Room Stereo set volume 11
Living Room Stereo is off
Living Room CeilingFan set medium
Living Room CeilingFan is off
Living Room CeilingFan set high
Living Room CeilingFan is off
~~~~~~~~~~~~~~~~~~~~~测试撤销
Living Room Light is on
Living Room Light is off
Living Room Light is on
Living Room Light is off
Living Room Light is on
Living Room Light is off
Living Room CeilingFan set medium
Living Room CeilingFan is off
Living Room CeilingFan set medium
Living Room CeilingFan set high
Living Room CeilingFan set medium
~~~~~~~~~~~~~~~~~~~~~测试宏命令

---------Remote Control----------
[slot 0] Command.LightOnCommand   Command.LightOffCommand
[slot 1] Command.LightOnCommand   Command.LightOffCommand
[slot 2] Command.GarageDoorOpenCommand   Command.GarageDoorDownCommand
[slot 3] Command.StereoOnWithCDCommand   Command.StereoOffCommand
[slot 4] Command.CeilingFanMediumCommand   Command.CeilingFanOffCommand
[slot 5] Command.CeilingFanHighCommand   Command.CeilingFanOffCommand
[slot 6] Command.MacroCommand   Command.MacroCommand

-----Pushing Macro On--------
Living Room Light is on
Kitchen Light is on
GarageDoor up
Living Room Stereo is on
Living Room Stereo set CD
Living Room Stereo set volume 11
Living Room CeilingFan set medium
-----Pushing Macro Of--------
Living Room Light is off
Kitchen Light is off
GarageDoor down
Living Room Stereo is off
Living Room CeilingFan is off
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 实例解析:已知一个遥控器有七个可编程的插槽(每个都可以指定到一个不同的家电装置),每个插槽都有对应的开关按钮。这个...
    Kwee阅读 259评论 0 0
  • 生活场景分析 今天来学习命令模式,先从一个生活中的例子入手吧,这样理解起来也比较容易。大家应该有用过那种万能遥控器...
    西木柚子阅读 722评论 2 6
  • 定义:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持撤销的操作。注意命令模...
    Knight_Davion阅读 138评论 0 0
  • 标签: python 设计模式 引子 命令模式其实仔细想想还是比较容易理解的,只是不知道我理解的对不对,按照书中的...
    plectrum阅读 1,963评论 1 10
  • 目录 本文的结构如下: 什么是命令模式 为什么要用该模式 模式的结构 代码示例 优点和缺点 适用环境 模式应用 总...
    w1992wishes阅读 1,097评论 2 9