Design Patterns: The Command Pattern in Java
by Riley MacDonald, August 29, 2017

Introduction
The command pattern is most commonly used in scenarios where commands or requests are made. Commands are encapsulated as Objects which simplifies maintenance and maximizes Objectextension.

Example Problem
As a side project I wrote an Android application which acts as a remote control for computers in my home. The application works by making an SSH connection and executing commands to trigger functions such as “play music” and “stop music”. I started writing the application in a POC (proof of concept) style. Most of the commands were strings being passed around to several methods. As more functionality and devices were added technical debt grew. Adding new commands and maintaining existing ones became tedious.

This example contains the following structure:

  • Command: Interface that represents a command
  • Concrete Command: Represents a specific command to be made such as “play music” or “stop music”
  • Invoker: Holds commands and executes them as needed (the toggle button listener for this example).
  • Client: The Application
  • Receiver: A class which knows how to execute the command (Computer for this example).

This post describes the basics of the command pattern without showing the internal details of the Receiver (Computer) class. Just know that Computer knows how to playMusic() or stopMusic() when it’s told to. Here’s the implementation of the command pattern:

Command Interface
Here’s the Command interface. It has an execute() method. All commands will implement this interface.

public interface Command {
    public void execute();
}

Concrete Command Object
Let’s write a couple concrete command Objects for our “play music” and “stop music” commands. Concrete command objects take the Receiver as a constructor argument.

public class PlayMusicCommand implements Command {
    Computer computer; // Receiver
 
    public PlayMusicCommand(Computer computer) {
        this.computer = computer;
    }
 
    @Override
    public void execute() {
        computer.playMusic();
    }
}
 
public class StopMusicCommand implements Command {
    Computer computer;
 
    public PlayMusicCommand(Computer computer) {
        this.computer = computer;
    }
 
    @Override
    public void execute() {
        computer.stopMusic();
    }
}

Invoker – Toggle Button Listener
The toggle button listener listens for clicks / touches and knows if it’s in an on or off state based on the isChecked boolean. The invoker doesn’t care about the details of the command it only cares about invoking execute().

public class ToggleButtonListener implements CompoundButton.OnCheckedChangeListener {
    private Command onCommand;
    private Command offCommand;
 
    public ToggleButtonListener(Command onCommand, Command offCommand) {
        this.onCommand = onCommand;
        this.offCommand = offCommand;
    }
 
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) offCommand.execute();
        else onCommand.execute();
    }
}

Client (Application)
Here’s a application with a ToggleButton that plays and stops music (Toggle Buttons have an on and off state). When a user turns the button to an on state music should start playing (on the living room computer).

public class MainActivity extends AppCompatActivity {
    // Receiver
    Computer livingRoomComputer = new LivingRoomComputer();
 
    // Command(s)
    Command playMusicCommand = new PlayMusicCommand(livingRoomComputer);
    Command stopMusicCommand = new StopMusicCommand(livingRoomComputer);
 
    // Invoker
    ToggleButtonListener playMusicToggleButtonListener = 
        new ToggleButtonListener(playMusicCommand, stopMusicCommand);
 
    // Client
    public void onCreate(Bundle savedInstanceState) {
        playMusicToggleButton.setOnCheckChangedListener(playMusicToggleButtonListener);
    }
}

Summary
While this example only covers on and off functionality it still shows the power of the command pattern. When new devices (Receivers) or commands are added the client can just write new implementations and extend functionality as needed.

Initially when I learned about this pattern my first concern was how many concrete Command implementations a large application might end up with. If you’re using Java 8+ you can pretty the command pattern using Lambda expressions. For example instead of the client writing concrete implementations of PlayMusicCommand and StopMusicCommand they can just inline it. This is allowed because Command has a single method execute(). The compiler knows to invoke execute() it just needs to know what the method body will be.

ToggleButtonListener playMusicToggleButtonListener = 
    new ToggleButtonListener(
        () -> livingRoomComputer.playMusic(),  // on command 
        () -> livingRoomComputer.stopMusic()); // off command
Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

Be the first to leave a comment on this post!