C++ Command Design Pattern Example

1. Definition

The Command Design Pattern encapsulates a request as an object, thereby allowing users to parameterize objects with different requests, queue requests, and support undoable operations.

2. Problem Statement

Imagine you're designing a menu system for a graphic application. Each menu item is associated with a specific action, such as drawing a shape or filling color. As the application evolves, you'll likely add new operations. How can you design this system to be flexible, extensible, and decoupled?

3. Solution

Encapsulate each operation in a command object. These objects have a common interface, allowing them to be executed, undone, or stored easily.

4. Real-World Use Cases

1. Undo and redo functionalities in software applications.

2. Task scheduling systems.

3. Remote control devices where each button is associated with a specific command.

5. Implementation Steps

1. Define a Command interface with an execute method.

2. Create one or more derived classes that encapsulate a receiver object and invoke the corresponding operation on it.

3. The client creates command objects and sets their receiver.

4. The invoker class asks the command to carry out the request.

6. Implementation in C++

// Step 1: Command Interface
class Command {
public:
    virtual ~Command() {}
    virtual void execute() const = 0;
};
// Step 2: Concrete Commands
class Light {
public:
    void turnOn() const {
        std::cout << "Light is ON" << std::endl;
    }
};
class LightOnCommand : public Command {
private:
    Light* light;
public:
    explicit LightOnCommand(Light* l) : light(l) {}
    void execute() const override {
        light->turnOn();
    }
};
// Step 3: Invoker
class RemoteControl {
private:
    Command* command;
public:
    void setCommand(Command* cmd) {
        command = cmd;
    }
    void pressButton() const {
        command->execute();
    }
};
int main() {
    Light* light = new Light();
    Command* lightOn = new LightOnCommand(light);
    RemoteControl remote;
    remote.setCommand(lightOn);
    remote.pressButton();
    delete light;
    delete lightOn;
    return 0;
}

Output:

Light is ON

Explanation:

1. Command is the interface for executing an operation.

2. Light is a receiver object. It has an action called turnOn.

3. LightOnCommand is a concrete command that encapsulates the Light and invokes the turnOn action on it.

4. RemoteControl acts as an invoker. It's provided with a command object which it can invoke when required.

In the main function, a Light object and its associated command LightOnCommand are created. The remote control is then given this command. When the pressButton method of remote is called, it triggers the command which in turn triggers the action on the Light object.

7. When to use?

Use the Command pattern when:

1. You need to decouple an object sending a request from the object which knows how to execute the request.

2. You want to parameterize objects with operations.

3. Operations need to be executed at different times or in different sequences.

4. You want to provide undo and redo functionality.


Comments