命令模式(Java版)

简介: 什么是命令模式?请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。将请求、命令、动作等封装成对象,这样可以让项目使用这些对象来参数化其他对象,使得命令的请求者和执行者解耦。

什么是命令模式?


请求命令的形式包裹在对象中,并传给调用对象

调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。

请求、命令、动作等封装成对象,这样可以让项目使用这些对象来参数化其他对象,使得命令的请求者和执行者解耦。

网络异常,图片无法展示
|

项目背景


现在我们有一个家电自动化遥控器项目,要求设置遥控器各个按钮,控制家电的不同的设备。怎样设计自动化遥控器才能保证遥控器的扩展性好、维护性好呢?

网络异常,图片无法展示
|


代码示例


网络异常,图片无法展示
|


看上面的UML类型,我们定义了设备动作类设备执行命令类,以及设备控制类

设备动作类

首先是定义电器设备类。

灯类(可以开关):

public class Light {
  String loc = "";
  public Light(String loc) {
    this.loc = loc;
  }
        // 开灯
  public void on() {
    System.out.println(loc + " On");
  }
        // 关灯
  public void off() {
    System.out.println(loc + " Off");
  }
}
复制代码

音响类(可以开关,打开cd,调大和降低音量):

// 音响
public class Stereo {
    static int volume = 0;
    //调节音量
    public void setVol(int vol) {
        volume = vol;
        System.out.println("Stereo volume=" + volume);
    }
    public int getVol() {
        return volume;
    }
    public void on() {
        System.out.println("Stereo On");
    }
    public void off() {
        System.out.println("Stereo Off");
    }
    // CD 播放
    public void setCd() {
        System.out.println("Stereo setCd");
    }
}
复制代码

设备执行命令类

然后定义电器设备命令类。

设备命令抽象接口:

public interface Command {
  // 执行
  void execute();
  // 回退
  void undo();
}
复制代码

不执行任何设备命令:

public class NoCommand implements Command {
  @Override
  public void execute() {
  }
  @Override
  public void undo() {
  }
}
复制代码

关灯:

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 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 StereoOffCommand implements Command {
    private Stereo setreo;
    public StereoOffCommand(Stereo setreo) {
        this.setreo = setreo;
    }
    @Override
    public void execute() {
        setreo.off();
    }
    @Override
    public void undo() {
        setreo.on();
        setreo.setCd();
    }
}
复制代码

开音响:

public class StereoOnCommand implements Command {
    private Stereo setreo;
    public StereoOnCommand(Stereo setreo) {
        this.setreo = setreo;
    }
    @Override
    public void execute() {
        setreo.on();
        setreo.setCd();
    }
    @Override
    public void undo() {
        setreo.off();
    }
}
复制代码

音响-增加音量:

public class StereoAddVolCommand implements Command {
    private Stereo setreo;
    public StereoAddVolCommand(Stereo setreo) {
        this.setreo = setreo;
    }
    @Override
    public void execute() {
        int vol = setreo.getVol();
        if (vol < 11) {
            setreo.setVol(++vol);
        }
    }
    @Override
    public void undo() {
        int vol = setreo.getVol();
        if (vol > 0) {
            setreo.setVol(--vol);
        }
    }
}
复制代码

音响-音量降低:

public class StereoSubVolCommand implements Command {
    private Stereo setreo;
    public StereoSubVolCommand(Stereo setreo) {
        this.setreo = setreo;
    }
    @Override
    public void execute() {
        int vol = setreo.getVol();
        if (vol > 0) {
            setreo.setVol(--vol);
        }
    }
    @Override
    public void undo() {
        int vol = setreo.getVol();
        if (vol < 11) {
            setreo.setVol(++vol);
        }
    }
}
复制代码

如果我们一个按钮想控制多个设备,定义如下类。

命令列表类:

public class MarcoCommand implements Command {
    private Command[] commands;
    public MarcoCommand(Command[] commands) {
        this.commands = commands;
    }
    @Override
    public void execute() {
        for (int i = 0, len = commands.length; i < len; i++) {
            commands[i].execute();
        }
    }
    @Override
    public void undo() {
        for (int i = commands.length - 1; i >= 0; i--) {
            commands[i].undo();
        }
    }
}
复制代码

设备控制类

最后定义设备控制类。

按钮控制抽象接口:

public interface Control {
    // 按钮开
    void onButton(int slot);
    // 按钮关
    void offButton(int slot);
    // 按钮回退
    void undoButton();
}
复制代码

具体设备控制类:

import java.util.Stack;
public class CommandModeControl implements Control {
    private Command[] onCommands;
    private Command[] offCommands;
    // 将执行过得命令放入栈中
    private Stack<Command> stack = new Stack<Command>();
    //初始化所有按钮槽不执行任何操作
    public CommandModeControl() {
        onCommands = new Command[5];
        offCommands = new Command[5];
        Command noCommand = new NoCommand();
        for (int i = 0, len = onCommands.length; i < len; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }
    // 定义每个槽的打开按钮和关闭按钮
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }
    // 执行打开操作
    @Override
    public void onButton(int slot) {
        onCommands[slot].execute();
        stack.push(onCommands[slot]);
    }
    // 执行关闭操作
    @Override
    public void offButton(int slot) {
        offCommands[slot].execute();
        stack.push(offCommands[slot]);
    }
    // 回退
    @Override
    public void undoButton() {
        stack.pop().undo();
    }
}
复制代码

执行结果

命令测试:

public class ControlTest {
    public static void main(String[] args) {
        CommandModeControl control = new CommandModeControl();
        Light bedroomlight = new Light("卧室灯");
        Light kitchlight = new Light("厨房灯");
        LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
        LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
        LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
        LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);
        // 批量操作灯的开关
        Command[] oncommands = {bedroomlighton, kitchlighton};
        Command[] offcommands = {bedroomlightoff, kitchlightoff};
        MarcoCommand onmarco = new MarcoCommand(oncommands);
        MarcoCommand offmarco = new MarcoCommand(offcommands);
        Stereo stereo = new Stereo();
        // 音响开关
        StereoOnCommand stereoOn = new StereoOnCommand(stereo);
        StereoOffCommand stereoOff = new StereoOffCommand(stereo);
        // 音响音量调节
        StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
        StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);
        // 卧室灯
        control.setCommand(0, bedroomlighton, bedroomlightoff);
        // 厨房灯
        control.setCommand(1, kitchlighton, kitchlightoff);
        // 音响开关
        control.setCommand(2, stereoOn, stereoOff);
        // 音响音量大小调节
        control.setCommand(3, stereoaddvol, stereosubvol);
        // 批量操作灯的开关
        control.setCommand(4, onmarco, offmarco);
        // 卧室开
        control.onButton(0);
        // 卧室关
        control.undoButton();
        // 厨房开
        control.onButton(1);
        // 厨房关
        control.offButton(1);
        // 音响开
        control.onButton(2);
        // 音响音量加
        control.onButton(3);
        // 音响音量减
        control.offButton(3);
        // 音响音量加
        control.undoButton();
        // 关音响
        control.offButton(2);
        // 开音响
        control.undoButton();
        // 批量开灯
        control.onButton(4);
        // 批量关关
        control.offButton(4);
    }
}
复制代码

输出结果:

卧室灯 On

卧室灯 Off

厨房灯 On

厨房灯 Off

Stereo On

Stereo setCd

Stereo volume=1

Stereo volume=0

Stereo volume=1

Stereo Off

Stereo On

Stereo setCd

卧室灯 On

厨房灯 On

卧室灯 Off

厨房灯 Off

总结


优点:

1、降低了系统耦合度。

2、新的命令可以很容易添加到系统中去。

缺点:

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

使用场景:

认为是命令的地方都可以使用命令模式,比如:

  1. GUI中每一个按钮都是一条命令。
  2. 模拟CMD。
相关文章
|
9月前
|
设计模式 小程序 Java
Java设计模式【十五】:命令模式
Java设计模式【十五】:命令模式
60 0
|
5月前
|
设计模式 存储 算法
Java设计模式-命令模式(16)
Java设计模式-命令模式(16)
|
6月前
|
设计模式 存储 Java
【十二】设计模式~~~行为型模式~~~命令模式(Java)
文章详细介绍了命令模式(Command Pattern),这是一种对象行为型模式,用于将请求封装成对象,实现请求发送者与接收者的解耦,从而降低系统耦合度、提高灵活性,并支持命令的排队、记录、撤销和恢复操作。通过案例分析、结构图、时序图和代码示例,文章展示了命令模式的组成部分、实现方式和应用场景,并讨论了其优点、缺点和适用情况。
|
8月前
|
设计模式 Java uml
必知的技术知识:JAVA【设计模式】命令模式
必知的技术知识:JAVA【设计模式】命令模式
38 0
|
8月前
|
设计模式 Java
Java设计模式之命令模式详解
Java设计模式之命令模式详解
|
9月前
|
设计模式 Java
23种设计模式,命令模式的概念优缺点以及JAVA代码举例
【4月更文挑战第7天】命令模式是一种行为设计模式,它将请求或简单操作封装为一个对象。这种模式允许用户通过调用对象来参数化其他对象的方法,并能保存、排队和执行方法调用。
78 1
|
9月前
|
设计模式 存储 Java
Java设计模式-命令模式
命令(Command)模式是指将请求封装成为一个对象,使发出请求和执行请求的责任分割开,方便将命令对象进行存储、传递、调用、增加与管理。 也就是将发送者、接收者和调用命令封装成独立的对象,来供客户端调用。属于行为模式的一种。
85 1
Java设计模式-命令模式
|
9月前
|
设计模式 Rust Java
命令模式 rust和java实现
命令模式 rust和java实现
80 0
|
设计模式 Java 调度
JAVA设计模式15:命令模式,将请求封装为对象,达到读写分离的效果
JAVA设计模式15:命令模式,将请求封装为对象,达到读写分离的效果
135 0
|
设计模式 Java API
【设计模式——学习笔记】23种设计模式——命令模式Command(原理讲解+应用场景介绍+案例介绍+Java代码实现)
【设计模式——学习笔记】23种设计模式——命令模式Command(原理讲解+应用场景介绍+案例介绍+Java代码实现)
167 0