The Command Design Pattern is a behavioral design pattern that turns a request into a stand-alone object containing information about the request. This decoupling allows the sender and the receiver to operate independently. The pattern is commonly used in scenarios where we need to decouple the invoker of a command from the object that knows how to execute the command.
Why Use the Command Pattern?
The Command Pattern offers several benefits:
- Decoupling: It decouples the classes that invoke the operation from the class that knows how to execute the operation.
- Flexibility: Commands can be executed immediately, scheduled, or logged.
- Extensibility: New commands can be added without altering existing code, adhering to the Open/Closed Principle.
Key Components of the Command Pattern
1. Command
This is an interface for executing an operation. It usually has a method named execute().
2. ConcreteCommand
This class extends the Command interface and implements the execute() method. It defines a binding between the action and the receiver.
3. Invoker
This class asks the command to execute the request.
4. Receiver
This is the actual class that performs the action associated with the command.
5. Client
The client class creates the command object and sets its receiver.
Implementing Command Pattern in Java
Let's delve into a practical example to understand the Command Pattern better.
// Command Interface
interface Command {
void execute();
}
// Concrete Command
class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
// Receiver
class Light {
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}
// Invoker
class RemoteControl {
Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// Client
public class CommandPatternDemo {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();
}
}In the above example, the Light class is the receiver, and it has methods to turn the light on and off. The LightOnCommand is a concrete command that implements the Command interface and overrides the execute() method. The RemoteControl class acts as the invoker, and the CommandPatternDemo class is the client.
Advantages and Disadvantages
Advantages:
- Decoupling: The invoker is decoupled from the receiver.
- Flexibility: Commands can be invoked in various ways, including immediate execution, delayed execution, or logging.
- Extensibility: New commands can be added without changing the existing code.
Disadvantages:
- Overhead: For every operation, a new command class is required, which can increase the number of classes.
Conclusion
The Command Design Pattern is a powerful tool in a developer's toolkit, especially when there's a need to decouple the sender and receiver or when operations need to be executed in various ways. By understanding and implementing this pattern, developers can write cleaner, more maintainable, and extensible code.