Command Pattern

Encapsulates a request as an object, allowing parameterization of clients with different requests, queuing or logging requests, and supporting undoable operations.

Example


// Device trait
trait Device {
    fn on(&self);
    fn off(&self);
}

// Light device
struct Light {
    name: String,
}

impl Device for Light {
    fn on(&self) {
        println!("{} light turned on", self.name);
        // Logic to turn on the light
    }

    fn off(&self) {
        println!("{} light turned off", self.name);
        // Logic to turn off the light
    }
}

// Thermostat device
struct Thermostat {
    name: String,
}

impl Device for Thermostat {
    fn on(&self) {
        println!("{} thermostat turned on", self.name);
        // Logic to turn on the thermostat
    }

    fn off(&self) {
        println!("{} thermostat turned off", self.name);
        // Logic to turn off the thermostat
    }
}

// Command trait
trait Command {
    fn execute(&self);
    fn undo(&self);
}

// Concrete command for turning on the device
struct TurnOnCommand<T: Device> {
    device: T,
}

impl<T: Device> Command for TurnOnCommand<T> {
    fn execute(&self) {
        self.device.on();
    }

    fn undo(&self) {
        self.device.off();
    }
}

// Concrete command for turning off the device
struct TurnOffCommand<T: Device> {
    device: T,
}

impl<T: Device> Command for TurnOffCommand<T> {
    fn execute(&self) {
        self.device.off();
    }

    fn undo(&self) {
        self.device.on();
    }
}

// Home automation system
struct HomeAutomation {
    commands: Vec<Box<dyn Command>>,
}

impl HomeAutomation {
    fn new() -> Self {
        HomeAutomation {
            commands: Vec::new(),
        }
    }

    fn add_command(&mut self, command: Box<dyn Command>) {
        self.commands.push(command);
    }

    fn execute_commands(&self) {
        for command in &self.commands {
            command.execute();
        }
    }

    fn undo_commands(&self) {
        for command in self.commands.iter().rev() {
            command.undo();
        }
    }
}

fn main() {
    let living_room_light = Light {
        name: "Living Room Light".to_string(),
    };
    let bedroom_light = Light {
        name: "Bedroom Light".to_string(),
    };
    let thermostat = Thermostat {
        name: "Thermostat".to_string(),
    };

    let turn_on_living_room_light = Box::new(TurnOnCommand {
        device: living_room_light,
    });
    let turn_off_bedroom_light = Box::new(TurnOffCommand {
        device: bedroom_light,
    });
    let turn_on_thermostat = Box::new(TurnOnCommand { device: thermostat });

    let mut home_automation = HomeAutomation::new();
    home_automation.add_command(turn_on_living_room_light);
    home_automation.add_command(turn_off_bedroom_light);
    home_automation.add_command(turn_on_thermostat);

    home_automation.execute_commands();
    println!("Undoing last command:");
    home_automation.undo_commands();
}