设计模式之命令模式

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

结构

命令模式结构
命令模式的主要角色有:

  • 命令(Command):为所有命令声明了一个接口。调用命令对象的 execute()方法,就可以让接收者进行相关的操作。这个接口也具备一个 undo() 方法。
  • 具体命令(ConcreteCommand):实现命令接口,定义了动作和接收者之间的绑定关系。调用者只要调用 execute() 就可以发出请求,然后由 ConcreteCommand 调用接收者的一个或多个动作。
  • 接收者(Receiver):接收者知道如何进行必要的动作,实现这个请求。任何类都可以当接收者。
  • 请求者(Invoker):持有一个命令对象,有一个行动方法,在某个时间点调用命令对象的 execute() 方法,将请求付诸实行。

优缺点

优点

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

缺点

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

代码实现

接收者

public class Light {

    public void on() {
        System.out.println("灯亮了...");
    }

    public void off() {
        System.out.println("灯暗了...");
    }
}

命令

public interface Command {
    // 执行命令
    void execute();

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

具体命令

public class LightOnCommand implements Command {

    private Light light;

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

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

    @Override
    public void undo() {
        light.off();
    }
}
public class LightOffCommand implements Command {

    private Light light;

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

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

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

请求者
前面,我们定义了动作的接收方和联系中介 —— 命名对象。现在,我们要着手构建请求者角色了。请求者持有一个命令对象,有一个行动方法。它会在某个时间点执行行动方法,但不关心是谁具体执行了这个动作。

public class RemoteInvoker {

    /**
     * 开关命令数组,模拟有很多对开关数组
     */
    private Command[] onCommands;
    private Command[] offCommands;
    /**
     * 撤销(回退)命令
     */
    private Command undoCommand;

    public RemoteInvoker(int length) {
        // 有几组开关,就设置多少数组
        onCommands = new Command[length];
        offCommands = new Command[length];
        // 把每个命令初始化成空命令,避免空指针异常
        Command noCommand = new NoCommand();
        undoCommand = noCommand;
        for (int i = 0; i < length; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }

    /**
     * @param slot 遥控器的位置
     * @param onCommand 开的命令
     * @param offCommand 关的命令
     * @return void
     */
    public void setCommond(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }


    public void onButton(int slot) {
        onCommands[slot].execute();
        //为撤销(回退)按钮记录动作
        undoCommand = onCommands[slot];
    }

    public void offButton(int slot) {
        offCommands[slot].execute();
        //为撤销(回退)按钮记录动作
        undoCommand = offCommands[slot];
    }

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

测试
前面,我们定义好了请求者、接收者已经两者之间的联系中介 —— 命令对象。但是这几个角色对象之间都是松耦合的,还没有一个具体动作的流程,现在我们利用客户端角色把整个动作流程串联在一起。

public class RemoteClient {

    public static void main(String[] args) {
        // 1、创建接收者
        Light light = new Light();
        // 2、创建命令对象
        LightOnCommand lightOnCommand = new LightOnCommand(light);
        LightOffCommand lightOffCommand = new LightOffCommand(light);
        // 3、创建一组开关并用命令对象装载它
        RemoteInvoker invoker = new RemoteInvoker(1);
        invoker.setCommond(0, lightOnCommand, lightOffCommand);
        // 4、测试
        invoker.onButton(0);
        invoker.offButton(0);
        invoker.undoButton();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值