This is the 10th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

What is command mode?

The request is wrapped in the object as a command and passed to the calling object.

The call object finds the appropriate object that can handle the command and passes the command to the appropriate object, which executes the command.

Encapsulating requests, commands, actions, and so on into objects allows the project to use these objects to parameterize other objects, decoupling the requester and the executor of the command.

Project background

Now we have a remote control project for home appliance automation, which requires setting the buttons of the remote control to control different devices of home appliances. How to design automatic remote control to ensure good expansibility and maintenance of the remote control?

Code sample

Looking at the UML type above, we define the device action class, the device execution command class, and the device control class.

Device Action class

The first is to define the electrical equipment class.

Light class (can switch) :

public class Light {

	String loc = "";

	public Light(String loc) {
		this.loc = loc;
	}
        / / turn on the light
	public void on(a) {
		System.out.println(loc + " On");
	}
        / / to turn off the lights
	public void off(a) {
		System.out.println(loc + " Off"); }}Copy the code

Audio class (can switch on and off, open CD, turn up and down volume) :

/ / sound
public class Stereo {

    static int volume = 0;
    // Adjust the volume
    public void setVol(int vol) {
        volume = vol;
        System.out.println("Stereo volume=" + volume);
    }

    public int getVol(a) {
        return volume;
    }

    public void on(a) {
        System.out.println("Stereo On");
    }

    public void off(a) {
        System.out.println("Stereo Off");
    }

    / / CD playback
    public void setCd(a) {
        System.out.println("Stereo setCd"); }}Copy the code

Device execution command class

Then define the electrical equipment command class.

Device command abstract interface:

public interface Command {

	/ / execution
	void execute(a);

	/ / back to back
	void undo(a);
}
Copy the code

Do not execute any device commands:

public class NoCommand implements Command {

	@Override
	public void execute(a) {}@Override
	public void undo(a) {}}Copy the code

Turn off the lights:

public class LightOffCommand implements Command {

    private Light light;

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

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

    @Override
    public void undo(a) { light.on(); }}Copy the code

Turn on the light:

public class LightOnCommand implements Command {

    private Light light;

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

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

    @Override
    public void undo(a) { light.off(); }}Copy the code

Close the sound:

public class StereoOffCommand implements Command {
    private Stereo setreo;

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

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

    @Override
    public void undo(a) { setreo.on(); setreo.setCd(); }}Copy the code

Open the sound:

public class StereoOnCommand implements Command {

    private Stereo setreo;

    public StereoOnCommand(Stereo setreo) {
        this.setreo = setreo;
    }

    @Override
    public void execute(a) {
        setreo.on();
        setreo.setCd();

    }

    @Override
    public void undo(a) { setreo.off(); }}Copy the code

Stereo – Increase the volume:

public class StereoAddVolCommand implements Command {

    private Stereo setreo;

    public StereoAddVolCommand(Stereo setreo) {
        this.setreo = setreo;
    }

    @Override
    public void execute(a) {
        int vol = setreo.getVol();
        if (vol < 11) { setreo.setVol(++vol); }}@Override
    public void undo(a) {
        int vol = setreo.getVol();
        if (vol > 0) { setreo.setVol(--vol); }}}Copy the code

Stereo – Volume down:

public class StereoSubVolCommand implements Command {

    private Stereo setreo;

    public StereoSubVolCommand(Stereo setreo) {
        this.setreo = setreo;
    }

    @Override
    public void execute(a) {
        int vol = setreo.getVol();
        if (vol > 0) { setreo.setVol(--vol); }}@Override
    public void undo(a) {
        int vol = setreo.getVol();
        if (vol < 11) { setreo.setVol(++vol); }}}Copy the code

If we want one button to control multiple devices, define the following class.

Command list class:

public class MarcoCommand implements Command {

    private Command[] commands;

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

    @Override
    public void execute(a) {
        for (int i = 0, len = commands.length; i < len; i++) { commands[i].execute(); }}@Override
    public void undo(a) {
        for (int i = commands.length - 1; i >= 0; i--) { commands[i].undo(); }}}Copy the code

Device Control

Finally, define the device control class.

Button control abstract interface:

public interface Control {

    / / button
    void onButton(int slot);

    / / button
    void offButton(int slot);

    // Button rollback
    void undoButton(a);
}
Copy the code

Specific device control class:

import java.util.Stack;


public class CommandModeControl implements Control {

    private Command[] onCommands;

    private Command[] offCommands;
    
    // Put the executed command on the stack
    private Stack<Command> stack = new Stack<Command>();

    // Initialize all button slots without performing any operations
    public CommandModeControl(a) {
        
        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; }}// Define the open and close buttons for each slot
    public void setCommand(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    // Perform the open operation
    @Override
    public void onButton(int slot) {
        onCommands[slot].execute();
        stack.push(onCommands[slot]);
    }

    // Perform the shutdown operation
    @Override
    public void offButton(int slot) {
        offCommands[slot].execute();
        stack.push(offCommands[slot]);
    }

    / / back to back
    @Override
    public void undoButton(a) { stack.pop().undo(); }}Copy the code

The execution result

Command test:

public class ControlTest {

    public static void main(String[] args) {
        CommandModeControl control = new CommandModeControl();

        Light bedroomlight = new Light("Bedroom light");
        Light kitchlight = new Light("Kitchen light");

        LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
        LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
        LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
        LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);

        // Operate the light switches in batches
        Command[] oncommands = {bedroomlighton, kitchlighton};
        Command[] offcommands = {bedroomlightoff, kitchlightoff};
        MarcoCommand onmarco = new MarcoCommand(oncommands);
        MarcoCommand offmarco = new MarcoCommand(offcommands);

        Stereo stereo = new Stereo();
        // Sound switch
        StereoOnCommand stereoOn = new StereoOnCommand(stereo);
        StereoOffCommand stereoOff = new StereoOffCommand(stereo);
        // Sound volume adjustment
        StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
        StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);

        / / the bedroom light
        control.setCommand(0, bedroomlighton, bedroomlightoff);
        / / the kitchen light
        control.setCommand(1, kitchlighton, kitchlightoff);
        // Sound switch
        control.setCommand(2, stereoOn, stereoOff);
        // Sound volume adjustment
        control.setCommand(3, stereoaddvol, stereosubvol);
        // Operate the light switches in batches
        control.setCommand(4, onmarco, offmarco);
        
        / / bedroom
        control.onButton(0);
        / / bedroom
        control.undoButton();

        / / open kitchen
        control.onButton(1);
        / / the kitchen
        control.offButton(1);
        
        / / stereo
        control.onButton(2);

        // Add the sound volume
        control.onButton(3);
        // Reduce the sound volume
        control.offButton(3);
        // Add the sound volume
        control.undoButton();

        / / off sound
        control.offButton(2);
        / / sound
        control.undoButton();
        
        // Turn on the lights in batches
        control.onButton(4);
        // Batch customs
        control.offButton(4); }}Copy the code

Output results:

The bedroom light On

The bedroom light Off

The kitchen light On

The kitchen light Off

Stereo On

Stereo setCd

Stereo volume=1

Stereo volume=0

Stereo volume=1

Stereo Off

Stereo On

Stereo setCd

The bedroom light On

The kitchen light On

The bedroom light Off

The kitchen light Off

conclusion

Advantages:

1, reduce the coupling degree of the system.

2. New commands can be easily added to the system.

Disadvantages:

Using command mode can cause some systems to have too many specific command classes.

Usage scenario:

You can use the command mode wherever you think it is a command, for example:

  1. Each button in the GUI is a command.
  2. Simulate the CMD.

Note:

If the system needs to support Undo and Redo operations, you can also use the command mode.