Command Design Pattern - Encapsulating Invocation

1. What Command Pattern defined

The Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operation.

Four terms are always associated with the command pattern, they are command, receiver, invoker and client. Let’s see them in detail.

Image source: Head First Design Patterns

1). Command object

It encapsulates a request by binding together a set of actions on a specific receiver. To achieve this, it packages the actions and the receiver up into an object that expoased just one method, execute(). When called, execute() causes the actions to be invoked on the receiver.
From the outside, no other objects really know that actions get performed on what receiver; they just know that if they call execute() method, their request will be serviced.

2). Receiver object:

The receiver object is also stored in command object. The recever does the work when the execute() method in command is called.

3). Invoker object:

An invoker object knows how to execute a command, and optionally does bookkeeping about the command execution. The invoker does not know anything about a concrete command, it knows only about the command interface.

4). Clinet object:

Invoker, command, and receiver objects are held by a client object, client decides which receiver it assigns to the command, and which command it assigns to the invoker. The client decides which commands to execute at which points. To execute a command, it passes the command to the invoker.

2. Application scenario

Command design pattern can solve these problems:

  • Coupling the invoker of a request to a particular request should be avoided.
  • It should be possible to configure an object (that invokes a request) with a request.

The solutions it provides are:

  • Define seperate (command) objects that encapsulate a request.
  • A class delegates a request to a common object instead of implementing a particular request directly.

3. Structure

Image source: Head First Design Patterns

4. Example

In this example, the task is to design an API for remote control of some devices in home like light, garage door… When user click a light on button then the light is turned on.

EXAMPLE
/*-----------entities----------------*/
/*
* Light has two function, turn on or turn off
* */
public class Light {
    public void on() {
        System.out.println("Turn light on.");
    }
    public void off() {
        System.out.println("Turn light off.");
    }
}

/*-----------command interface----------------*/
/*
* Command Interface
* */
public interface Command {
    public void execute();
}

/*-----------concrete command class------------*/
/*
* Command to turn on light
* */
public class LightOnCommand implements Command {

    Light light;

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

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

/*
 * Command to turn off light
 * */
public class LightOffCommand implements Command {

    Light light;

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

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

/*-------------------invoker-------------------*/
/*
* invoker: used to set commands
* */
public class RemoteControl {
    Command[] onCommands;
    Command[] offCommands;

    public RemoteControl() {
        this.onCommands = new Command[2];
        this.offCommands = new Command[2];

        Command noCommand = new NoCommand();
        for (int i = 0; i < 2; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
    }

    public void setCommands(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
    }

    public void offButtonWasPushed(int slot) {
        offCommands[slot].execute();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("\n---------- Remote Control --------\n");

        for (int i = 0; i < onCommands.length; i++)
            sb.append("slot: " + i + ", " + onCommands[i].getClass().getName() +
                    "   " + offCommands.getClass().getName() + "\n");

        return sb.toString();
    }
}

/*-------------------client-------------------*/
/*
* client: hold the command, receiver, and invoker objects
* */
public class RemoteLoader {

    public static void main(String[] args) {

        // Create all the devices
        Light light = new Light();

        // Create all the light command objects
        Command lightOnCommand = new LightOnCommand(light);
        Command lightOffCommand = new LightOffCommand(light);

        // load commands to the remote slots
        RemoteControl remoteControl = new RemoteControl();
        remoteControl.setCommands(0, lightOnCommand, lightOffCommand);

        System.out.println(remoteControl);

        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);


    }
}

The result is shown as follows.

5. Conclusion

  • The Command Pattern decouples an object, making a request from the one that knows how to perform it.
  • The command object is at the center of this decoupling and encapsulates a receiver with an action (or set of actions).
  • An invoker makes a request of a Command object by calling its execute() method, which invokes those actions on the receiver.
  • Invokers can be parameterized with Coammands, even dynamically at runtime.
  • Support Undo.

   Reprint policy


《Command Design Pattern - Encapsulating Invocation》 by Tong Shi is licensed under a Creative Commons Attribution 4.0 International License
  TOC