Skip to content

Latest commit

 

History

History
212 lines (173 loc) · 5.46 KB

File metadata and controls

212 lines (173 loc) · 5.46 KB

Command

Analogy

A restaurant order decouples the customer (who requests food) from the chef (who prepares it). The waiter writes an order ticket — a Command object containing all the details — and places it in the kitchen queue. This allows orders to be queued, prioritized, logged, and even undone (canceled order). The Command pattern similarly encapsulates a request as an object, enabling parameterization, queuing, logging, and undo/redo operations.

Intent

Turns a request into a standalone object containing all information about the request. This lets you parameterize methods, delay execution, or queue operations.

Structure

  • Command: Declares an interface for executing an operation, typically with an execute() method.
  • ConcreteCommand: Defines a binding between a Receiver object and an action. Implements execute() by invoking the corresponding operation on the Receiver.
  • Invoker: Asks the command to carry out the request. Optionally stores and manages commands for undo/redo.
  • Receiver: Knows how to perform the actual work.
  • Client: Creates ConcreteCommand objects and associates them with receivers.

C++

#include <iostream>
#include <memory>
#include <stack>
#include <string>

class Light {
public:
    void on()  { std::cout << "Light is ON\n";  state_ = true; }
    void off() { std::cout << "Light is OFF\n"; state_ = false; }
    bool state() const { return state_; }
private:
    bool state_ = false;
};

class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
    virtual void undo() = 0;
};

class LightOnCommand : public Command {
public:
    explicit LightOnCommand(std::shared_ptr<Light> light) : light_(std::move(light)) {}
    void execute() override { light_->on(); }
    void undo() override    { light_->off(); }
private:
    std::shared_ptr<Light> light_;
};

class LightOffCommand : public Command {
public:
    explicit LightOffCommand(std::shared_ptr<Light> light) : light_(std::move(light)) {}
    void execute() override { light_->off(); }
    void undo() override    { light_->on(); }
private:
    std::shared_ptr<Light> light_;
};

class RemoteControl {
public:
    void setCommand(std::shared_ptr<Command> cmd) { command_ = std::move(cmd); }
    void pressButton() {
        if (command_) {
            history_.push(command_);
            command_->execute();
        }
    }
    void pressUndo() {
        if (!history_.empty()) {
            auto cmd = history_.top();
            history_.pop();
            cmd->undo();
        }
    }
private:
    std::shared_ptr<Command> command_;
    std::stack<std::shared_ptr<Command>> history_;
};

int main() {
    auto light = std::make_shared<Light>();
    auto onCmd  = std::make_shared<LightOnCommand>(light);
    auto offCmd = std::make_shared<LightOffCommand>(light);

    RemoteControl remote;
    remote.setCommand(onCmd);
    remote.pressButton();
    remote.setCommand(offCmd);
    remote.pressButton();

    remote.pressUndo();
    remote.pressUndo();
}

JavaScript

class Light {
    constructor() { this.isOn = false; }
    on()  { this.isOn = true;  console.log('Light is ON'); }
    off() { this.isOn = false; console.log('Light is OFF'); }
}

class LightOnCommand {
    constructor(light) { this.light = light; }
    execute() { this.light.on(); }
    undo()    { this.light.off(); }
}

class LightOffCommand {
    constructor(light) { this.light = light; }
    execute() { this.light.off(); }
    undo()    { this.light.on(); }
}

class RemoteControl {
    constructor() {
        this.command = null;
        this.history = [];
    }

    setCommand(command) { this.command = command; }

    pressButton() {
        if (this.command) {
            this.history.push(this.command);
            this.command.execute();
        }
    }

    pressUndo() {
        const cmd = this.history.pop();
        if (cmd) cmd.undo();
    }
}

const light = new Light();
const onCmd  = new LightOnCommand(light);
const offCmd = new LightOffCommand(light);

const remote = new RemoteControl();
remote.setCommand(onCmd);
remote.pressButton();
remote.setCommand(offCmd);
remote.pressButton();

remote.pressUndo();
remote.pressUndo();

TypeScript

interface Command {
    execute(): void;
    undo(): void;
}

class Light {
    private _isOn = false;
    get isOn(): boolean { return this._isOn; }
    on(): void  { this._isOn = true;  console.log('Light is ON'); }
    off(): void { this._isOn = false; console.log('Light is OFF'); }
}

class LightOnCommand implements Command {
    constructor(private light: Light) {}
    execute(): void { this.light.on(); }
    undo(): void    { this.light.off(); }
}

class LightOffCommand implements Command {
    constructor(private light: Light) {}
    execute(): void { this.light.off(); }
    undo(): void    { this.light.on(); }
}

class RemoteControl {
    private command: Command | null = null;
    private history: Command[] = [];

    setCommand(cmd: Command): void { this.command = cmd; }

    pressButton(): void {
        if (this.command) {
            this.history.push(this.command);
            this.command.execute();
        }
    }

    pressUndo(): void {
        const cmd = this.history.pop();
        if (cmd) cmd.undo();
    }
}

const light = new Light();
const onCmd  = new LightOnCommand(light);
const offCmd = new LightOffCommand(light);

const remote = new RemoteControl();
remote.setCommand(onCmd);
remote.pressButton();
remote.setCommand(offCmd);
remote.pressButton();

remote.pressUndo();
remote.pressUndo();