设计模式——命令模式

命令模式是什么?

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

命令模式解决什么问题?

现有智能家居Tv和Light,万能遥控器可以控制家居,遥控器每排有开关两个按钮,最后还有一个撤销按钮,假设第一排的开关用于Tv,第二排的开关用于Light:

class Tv {

    public void TvOn() {
        System.out.println("开电视");
    }

    public void TvOff() {
        System.out.println("关电视");
    }
}

class Light {
    public void LightOn() {
        System.out.println("开灯");
    }

    public void LightOff() {
        System.out.println("关灯");
    }
}

public class RemoteControl {
    private Tv tv;
    private Light light;

    public void setTv(Tv tv) {
        this.tv = tv;
    }

    public void setLight(Light light) {
        this.light = light;
    }

    public void row1On() {
        if (tv != null) {
            tv.TvOn();
        }
    }

    public void row1Off() {
        if (tv != null) {
            tv.TvOff();
        }
    }

    public void row2On() {
        if (light != null) {
            light.LightOn();
        }
    }

    public void row2Off() {
        if (light != null) {
            light.LightOff();
        }
    }
}

调用过程:

Tv  tv=new Tv();
RemoteControl  rc=new RemoteControl();
rc.setTv(tv);
rc.row1On();
rc.row1Off();
  • problem1:按钮对应的开关事件不能动态改变
  • problem2:每当增加新家居时,都要修改源代码设置开关事件
  • problem3:撤销按钮事件难以维护

命令模式实现

命令接口

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

命令实现

保持Light和Tv源代码不变,封装OnCommand和OffCommand,重写execute()调用开或关,重写undo()调用相反的操作:

class TvOnCommand implements Command {

    Tv tv;

    public TvOnCommand(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.TvOn();
    }

    @Override
    public void undo() {
        tv.TvOff();
    }
}

class TvOffCommand implements Command {

    Tv tv;

    public TvOffCommand(Tv tv) {
        this.tv = tv;
    }

    @Override
    public void execute() {
        tv.TvOff();
    }

    @Override
    public void undo() {
        tv.TvOn();
    }
}

class LightOnCommand implements Command {

    Light light;

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

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

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

class LightOffCommand implements Command {

    Light light;

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

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

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

空命令

加入空命令可避免接下来在RemoteControl 中判断命令是否存在:

class NoCommand implements Command{

    @Override
    public void execute() {
        
    }

    @Override
    public void undo() {

    }
}

命令调用者

修改RemoteControl,通过构造函数传入遥控器行数,方便以后扩展,将全部先设为noCommand避免判空,setCommand()设置行数对应的开关事件,按完按钮后记录撤销事件:

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

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

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

    public void buttonOn(int row) {
        onCommands[row].execute();
        undoCommand = onCommands[row];
    }

    public void buttonOff(int row) {
        offCommands[row].execute();
        undoCommand = offCommands[row];
    }
    public void undo(){
        undoCommand.execute();
    }
}

命令过程

Light light=new Light();
LightOnCommand lightOn=new LightOnCommand(light);
LightOffCommand lightOff=new LightOffCommand(light);

RemoteControl rc=new RemoteControl();
rc.setCommand(0,lightOn,lightOff);
rc.buttonOn(0);
rc.buttonOff(0);
rc.undo();

组合命令

利用组合命令可以实现一连串的命令过程,如智能家居的电影模式、温馨模式

class CombinationCommand implements Command {
    Command[] commands;

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

    @Override
    public void execute() {
        for (int i = 0; i < commands.length; i++) {
            commands[i].execute();
        }
    }

    @Override
    public void undo() {
        for (int i = 0; i < commands.length; i++) {
            commands[i].undo();
        }
    }
}

组合和命令过程

Light light=new Light();
LightOnCommand lightOn=new LightOnCommand(light);
LightOffCommand lightOff=new LightOffCommand(light);

Tv tv=new Tv();
TvOnCommand tvOn=new TvOnCommand(tv);
TvOffCommand tvOff=new TvOffCommand(tv);

Command[] combinationOn={lightOn,tvOn};
Command[] combinationOff={lightOff,tvOff};

RemoteControl rc=new RemoteControl();
rc.setCommand(0,combinationOn,combinationOff);
rc.buttonOn(0);
rc.buttonOff(0);
rc.undo();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值