Java programming language logo

Command Design Pattern

The Command pattern is used for executing requests. Requests are implemented by command objects. A given command object knows how to execute a given request. The commands are executed by a command processor.

The Command Pattern decouples the object that making the request from the one that executes it.

Optionally, Command pattern can support undo operation that undoes the effect of the previous command or commands.

Command objects implement a common interface and contain the logic and other objects those needed to fulfill the requests. Every command is attached to an event source, for example, to a button. When the button is pressed, its attached command is executed.

Command pattern is a behavioral pattern.

Example

The next Java example is about a car that provides shortcut buttons for its owner to customize the car. For example, if the owner regularly turns on the seat heating and sets it to a high degree, there is an availability to create a shortcut button for this. Another example could be when the navigation is used frequently with the same destination. It’s much easier to create a "take me home" button instead of turning on the navigation and providing the same address every time.

The command is in the center of this pattern. In this simple example, the Command interface has only one method.


package com.programcodex.designpatterns.command;

public interface Command {

    public void execute();
}

Before creating exciting implementations for this interface, we are going to create the default one.

The NoCommand class does nothing. This represents the default states of the shortcuts buttons before any customization. With the help of this, there is no need for null check when a button is pressed. Initially the NoCommand is assigned to each button.


package com.programcodex.designpatterns.command;

public class NoCommand implements Command {

    @Override
    public void execute() {
        System.out.println("This button is not in use.");
    }
}

Next is the Shortcuts class. It provides 9 shortcut buttons. Every shortcut has an on and off button. The on and off commands are stored in the onCmds and offCmds arrays. In the constructor, these arrays are instantiated and filled up with a NoCommand instance.

The setCommand method assigns a command to a shortcut button. In the parameters, it receives the desired button number and the on-off commands. Obviously, it's convenient to turn on the seat heating with one button, but we also want to turn it off in the same way.

The pushOnButton and pushOffButton methods do exactly that their names suggest. These methods are called when the user presses a shortcut button.


package com.programcodex.designpatterns.command;

import java.util.Arrays;

public class Shortcuts {

    private final int BUTTONS_NUM = 9;
    private final Command[] onCmds;
    private final Command[] offCmds;

    public Shortcuts() {
        onCmds = new Command[BUTTONS_NUM];
        offCmds = new Command[BUTTONS_NUM];
        
        Command noCmd = new NoCommand();
        Arrays.fill(onCmds, noCmd);
        Arrays.fill(offCmds, noCmd);
    }

    public void setCommand(int buttonNum, Command onCmd, Command offCmd) {
        if (isBtnValid(buttonNum)) {
            onCmds[buttonNum] = onCmd;
            offCmds[buttonNum] = offCmd;
        }
    }

    public void pushOnButton(int buttonNum) {
        if (isBtnValid(buttonNum)) {
            onCmds[buttonNum].execute();
        }
    }

    public void pushOffButton(int buttonNum) {
        if (isBtnValid(buttonNum)) {
            offCmds[buttonNum].execute();
        }
    }

    private boolean isBtnValid(int buttonNum) {
        return buttonNum >= 0 && buttonNum < BUTTONS_NUM;
    }
}

The last class before creating the first real command is the SeatHeater class. Seat heating can be turned on and off, and its intensity can be changed. It provides three degrees of heating.


package com.programcodex.designpatterns.command;

public class SeatHeater {

    private int intensity = 0;
    
    public void on() {
        intensity = 1;
        System.out.println("Seat heating is on.");
    }
    
    public void off() {
        intensity = 0;
        System.out.println("Seat heating is off.");
    }
    
    public void changeIntensity() {
        intensity++;
        if (intensity > 3) {
            intensity = 1;
        }
        
        System.out.format("Intensity set to %d.%n", intensity);
    }
}

It’s time to create the "seat heating on" command. The SeatHeatingOnCmd class implements the Command interface. This class receives an instance of the SeatHeater class, and in the execute method fulfills the request by calling its methods. It does three steps. Turns on the seat heating and raises its intensity in two steps.


package com.programcodex.designpatterns.command;

public class SeatHeatingOnCmd implements Command {

    private SeatHeater seatHeater;

    public SeatHeatingOnCmd(SeatHeater seatHeater) {
        this.seatHeater = seatHeater;
    }

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

The pair of the SeatHeatingOnCmd class is the SeatHeatingOffCmd class, which is much simpler. It turns off the seat heating.


package com.programcodex.designpatterns.command;

public class SeatHeatingOffCmd implements Command {

    private SeatHeater seatHeater;

    public SeatHeatingOffCmd(SeatHeater seatHeater) {
        this.seatHeater = seatHeater;
    }

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

The next example for a command object is about navigation. First of all, we need the Navigation class. A navigation can be turned on and off, a destination can be set, and when everything is provided, the navigation can be started.


package com.programcodex.designpatterns.command;

public class Navigation {

    private String destination;
    
    public void on() {
        System.out.println("Navigation is on.");
    }
    
    public void off() {
        System.out.println("Navigation is off.");
    }

    public void setDestination(String destination) {
        this.destination = destination;
        System.out.format("Destination is set to %s.%n", destination);
    }
    
    public void start() {
        System.out.println("Navigation has been started.");
    }
}

The NavigateHomeCmd also implements the Command interface. It receives an instance of the Navigation class. This works exactly in the same way as the previous commands. In the execute method, it turns on the navigation, sets the home address and starts the navigation.


package com.programcodex.designpatterns.command;

public class NavigateHomeCmd implements Command {

    private Navigation navigation;

    public NavigateHomeCmd(Navigation navigation) {
        this.navigation = navigation;
    }

    @Override
    public void execute() {
        navigation.on();
        navigation.setDestination("671 Lincoln Avenue");
        navigation.start();
    }
}

The off command of the above class is the NavigationOffCmd.


package com.programcodex.designpatterns.command;

public class NavigationOffCmd implements Command {

    private Navigation navigation;

    public NavigationOffCmd(Navigation navigation) {
        this.navigation = navigation;
    }

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

And we are done. It’s time to run these things.

The test class instantiates the SeatHeater class and the on and off commands for it. After that, it instantiates the Navigation class and the commands for it.

When the commands are ready, it creates a Shortcuts instance and sets the commands by its setCommand method. The seat heating is assigned to the first shortcut button, the navigate home function to the second button.

Finally, the buttons get pressed several times for testing.


package com.programcodex.designpatterns.command;

public class TestCommand {

    public static void main(String[] args) {
        SeatHeater seatHeater = new SeatHeater();
        Command seatHeatingOnCmd =
                new SeatHeatingOnCmd(seatHeater);
        Command seatHeatingOffCmd =
                new SeatHeatingOffCmd(seatHeater);
        
        Navigation navigation = new Navigation();
        Command navigateHomeCmd =
                new NavigateHomeCmd(navigation);
        Command navigationOffCmd =
                new NavigationOffCmd(navigation);
        
        Shortcuts shortcuts = new Shortcuts();
        shortcuts.setCommand(0, seatHeatingOnCmd, seatHeatingOffCmd);
        shortcuts.setCommand(1, navigateHomeCmd, navigationOffCmd);
        
        System.out.println("Let's push the first shortcut button.");
        shortcuts.pushOnButton(0);
        
        System.out.println("\nLet's push the second shortcut button.");
        shortcuts.pushOnButton(1);
        
        System.out.println("\nLet's push the third shortcut button.");
        shortcuts.pushOnButton(2);
        
        System.out.println("\nNow let's push the off buttons.");
        shortcuts.pushOffButton(0);
        shortcuts.pushOffButton(1);
        shortcuts.pushOffButton(2);
    }
}

The output of the above test class:

The Command Design Pattern