- It encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
- The Command design pattern encapsulates an action or a request as an object.
- This pattern referred to "Action" or "Transaction" as well.
- The classic usage of this pattern is a menu system where each command object represents an action and an associated undo action.
- Each of which gets mapped to its own command object.
- All Commands implement the same interface, so they can be handled polymorphically.
- Typically their interface includes methods such as Execute and Undo.
Participants
Receiver
(Light)
- Knows how to perform the operations associated with carrying out the request.
Command
(ICommand)
- Declares an interface for executing an operation.
ConcreteCommand
(FlipUpCommand, FlipDownCommand)
- Defines a binding between a
Receiver
object and an action.
- Implements Execute by invoking the corresponding operation(s) on
Receiver
.
Invoker
(LightSwitch)
- Asks the
Command
to carry out the request.
var light = new Light();
ICommand switchUp = new FlipUpCommand(light);
ICommand switchDown = new FlipDownCommand(light);
var lightSwitch = new LightSwitch();
lightSwitch.StoreAndExecute(switchUp);
lightSwitch.StoreAndExecute(switchDown);
public class Light
{
public void TurnOn() => Console.WriteLine("The light is on");
public void TurnOff() => Console.WriteLine("The light is off");
}
public interface ICommand
{
void Execute();
}
public class LightSwitch
{
private List<ICommand> _Commands = new List<ICommand>();
public void StoreAndExecute(ICommand command)
{
_Commands.Add(command);
command.Execute();
}
}
public class FlipUpCommand : ICommand
{
private Light _Light;
public FlipUpCommand(Light light) => _Light = light;
public void Execute() => _Light.TurnOn();
}
public class FlipDownCommand : ICommand
{
private Light _Light;
public FlipDownCommand(Light light) => _Light = light;
public void Execute() => _Light.TurnOff();
}
Rules of Thumb
- Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs.
- Command normally specifies a sender-receiver connection with a subclass.
- Chain of Responsibility can use Command to represent requests as objects.
- Command and Memento act as magic tokens to be passed around and invoked at a later time.
- In Command, the token represents a request.
- In Memento, it represents the internal state of an object at a particular time.
- Polymorphism is important to Command, but not to Memento because its interface is so narrow that a memento can only be passed as a value.
- Command can use Memento to maintain the state required for an undo operation.
- MacroCommands can be implemented with Composite.
- A Command that must be copied before being placed on a history list acts as a Prototype.
- Two important aspects of the Command pattern:
- Interface separation (the invoker is isolated from the receiver).
- Time separation (stores a ready-to-go processing request that’s to be stated later).
Composite command pattern