Command Design Pattern
The Command Design Pattern is a behavioral design pattern that turns a request into a stand-alone object that contains all information about the request. This transformation allows for parameterization of methods with different requests, queuing of requests, and logging of the requests. It also provides support for undoable operations.
Components of Command Pattern
- Command: Declares an interface for executing an operation.
- ConcreteCommand: Implements the Command interface and defines a binding between a Receiver object and an action.
- Client: Creates a ConcreteCommand object and sets its receiver.
- Invoker: Asks the command to carry out the request.
- Receiver: Knows how to perform the operations associated with carrying out a request.
Here is an example of the Command Design Pattern:
use std::cell::RefCell; use std::rc::Rc; // Command pub trait Command { fn execute(&self); } // ConcreteCommand for turning on the light pub struct TurnOnCommand { pub light: Rc<RefCell<Light>>, } impl Command for TurnOnCommand { fn execute(&self) { self.light.borrow_mut().turn_on(); } } // ConcreteCommand for turning off the light pub struct TurnOffCommand { pub light: Rc<RefCell<Light>>, } impl Command for TurnOffCommand { fn execute(&self) { self.light.borrow_mut().turn_off(); } } // Invoker pub struct RemoteControl{ command: Option<Box<dyn Command>>, } impl RemoteControl { pub fn new() -> Self { RemoteControl { command: None } } pub fn set_command(&mut self, command: Box<dyn Command >) { self.command = Some(command); } pub fn press_button(&mut self) { if let Some(ref mut command) = self.command { command.execute(); } } } // Receiver pub struct Light { is_on: bool, } impl Light { pub fn new() -> Self { Light { is_on: false } } pub fn turn_on(&mut self) { self.is_on = true; println!("The light is on"); } pub fn turn_off(&mut self) { self.is_on = false; println!("The light is off"); } pub fn is_on(&self) -> bool { self.is_on } } // Client fn main() { let light = Rc::new(RefCell::new(Light::new())); let turn_on_command = TurnOnCommand { light: Rc::clone(&light) }; let turn_off_command = TurnOffCommand { light: Rc::clone(&light) }; let mut remote = RemoteControl::new(); remote.set_command(Box::new(turn_on_command)); remote.press_button(); println!("Light Status: {}", light.borrow().is_on()); // Borrow the Light instance remote.set_command(Box::new(turn_off_command)); remote.press_button(); println!("Light Status: {}", light.borrow().is_on()); // Borrow the Light instance }
In this example:
Command
is a trait that declares theexecute
method.Light
is the receiver that knows how to perform the operations.TurnOnCommand
andTurnOffCommand
are concrete commands that implement theCommand
trait.RemoteControl
is the invoker that triggers the commands.
This pattern decouples the object that invokes the operation from the one that knows how to perform it.