The Command is an interesting pattern where two objects can communicate through commands. The advantage is decoupling the object from its behavior (commands).

In this example, the RemoteControl creates slots with commands for Light and Fan named LightOnCommand, LightOffCommand, and FanSpeedCommand.

#include <iostream>
#include <vector>
#include <memory>
#include <stack>

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

class Light {
private:
    bool isOn = false;
    
public:
    void turnOn() { 
        isOn = true;
        std::cout << "๐Ÿ’ก Light is ON" << std::endl; 
    }
    
    void turnOff() { 
        isOn = false;
        std::cout << "๐Ÿ’ก Light is OFF" << std::endl; 
    }
    
    bool getState() const { return isOn; }
};

class Fan {
private:
    int speed = 0; 
    
public:
    void setSpeed(int s) {
        speed = s;
        if (speed == 0) {
            std::cout << "๐ŸŒ€ Fan is OFF" << std::endl;
        } else {
            std::cout << "๐ŸŒ€ Fan speed set to " << speed << std::endl;
        }
    }
    
    int getSpeed() const { return speed; }
};

class LightOnCommand : public Command {
private:
    Light* light;
    
public:
    LightOnCommand(Light* l) : light(l) {}
    
    void execute() override { 
        light->turnOn(); 
    }
    
    void undo() override { 
        light->turnOff(); 
    }
};

class LightOffCommand : public Command {
private:
    Light* light;
    
public:
    LightOffCommand(Light* l) : light(l) {}
    
    void execute() override { 
        light->turnOff(); 
    }
    
    void undo() override { 
        light->turnOn(); 
    }
};

class FanSpeedCommand : public Command {
private:
    Fan* fan;
    int newSpeed;
    int previousSpeed;
    
public:
    FanSpeedCommand(Fan* f, int speed) : fan(f), newSpeed(speed) {}
    
    void execute() override { 
        previousSpeed = fan->getSpeed();
        fan->setSpeed(newSpeed); 
    }
    
    void undo() override { 
        fan->setSpeed(previousSpeed); 
    }
};

class NoCommand : public Command {
public:
    void execute() override { 
        std::cout << "โš ๏ธ  No command assigned" << std::endl; 
    }
    
    void undo() override { 
        std::cout << "โš ๏ธ  Nothing to undo" << std::endl; 
    }
};


class RemoteControl {
private:
    std::vector<std::unique_ptr<Command>> onCommands;
    std::vector<std::unique_ptr<Command>> offCommands;
    static const int NUM_SLOTS = 4;
    
public:
    RemoteControl() {
        
        for (int i = 0; i < NUM_SLOTS; i++) {
            onCommands.push_back(std::make_unique<NoCommand>());
            offCommands.push_back(std::make_unique<NoCommand>());
        }
    }
    
    void setCommand(int slot, std::unique_ptr<Command> onCommand, 
                   std::unique_ptr<Command> offCommand) {
        if (slot >= 0 && slot < NUM_SLOTS) {
            onCommands[slot] = std::move(onCommand);
            offCommands[slot] = std::move(offCommand);
        }
    }
    
    void onButtonPressed(int slot) {
        if (slot >= 0 && slot < NUM_SLOTS) {
            onCommands[slot]->execute();
        }
    }
    
    void offButtonPressed(int slot) {
        if (slot >= 0 && slot < NUM_SLOTS) {
            offCommands[slot]->execute();
        }
    }
};

int main() {
    Light livingRoomLight;
    Fan ceilingFan;
    
    RemoteControl remote;
    
    remote.setCommand(0, 
        std::make_unique<LightOnCommand>(&livingRoomLight),
        std::make_unique<LightOffCommand>(&livingRoomLight)
    );
    
    remote.setCommand(1,
        std::make_unique<FanSpeedCommand>(&ceilingFan, 3),
        std::make_unique<FanSpeedCommand>(&ceilingFan, 0)
    );
    
    remote.onButtonPressed(0);   
    remote.offButtonPressed(0);  
    
    remote.onButtonPressed(1);   
    remote.offButtonPressed(1);  
    
    return 0;
}