In this post, we’ll delve into the Command Design Pattern, a behavioral design pattern that encapsulates requests as objects, allowing for parameterization and queuing of requests, and providing additional functionalities like undo and redo operations.
Table of contents
Open Table of contents
Sections
The Problem: Tight Coupling
Consider a graphical user interface (GUI) program with various UI elements like buttons, text fields, and boxes. Traditionally, these UI elements would directly invoke operations in the business logic. However, this leads to tight coupling, where the UI components need to know specifics about the business logic, resulting in a less maintainable and extensible system.
The Solution: Command Design Pattern
The Command Design Pattern addresses this issue by introducing a middle layer—a command—between the UI components and the business logic. Each command wraps an object and all the required information to process that command. These commands are then passed to the appropriate handler in the business logic.
Key Elements of the Pattern
Command Interface:
This interface defines the execute method, which encapsulates the action to be performed.
Concrete Commands:
Classes that implement the Command interface and contain the necessary information to execute a specific action.
Invoker:
The component that triggers the execution of a command.
Receiver:
The component that performs the actual processing of the command.
Implementation Example
Let’s illustrate the pattern with a simple order processing system. We’ll have two types of commands: OrderAddCommand and OrderExecuteCommand. Both will implement the Command interface.
Command Interface
public interface Command {
void execute();
}
Concrete Commands
OrderAddCommand
public class OrderAddCommand implements Command {
private int id;
private double price;
public OrderAddCommand(int id, double price) {
this.id = id;
this.price = price;
}
@Override
public void execute() {
System.out.println("Order " + id + " added with price " + price);
}
}
OrderExecuteCommand
public class OrderExecuteCommand implements Command {
private int id;
public OrderExecuteCommand(int id) {
this.id = id;
}
@Override
public void execute() {
System.out.println("Order " + id + " executed");
}
}
Command Processor
import java.util.ArrayList;
import java.util.List;
public class CommandProcessor {
private List<Command> commands = new ArrayList<>();
public void addCommand(Command command) {
commands.add(command);
}
public void processCommands() {
for (Command command : commands) {
command.execute();
}
}
}
Client Code
public class Client {
public static void main(String[] args) {
CommandProcessor processor = new CommandProcessor();
processor.addCommand(new OrderAddCommand(1, 1299.0));
processor.addCommand(new OrderAddCommand(2, 1599.0));
processor.addCommand(new OrderExecuteCommand(1));
processor.addCommand(new OrderExecuteCommand(2));
processor.processCommands();
}
}
Conclusion
The Command Design Pattern is a powerful tool that helps in decoupling the invoker from the receiver, providing flexibility, and enabling additional functionalities like undo and redo operations. By encapsulating requests as objects, it enhances maintainability and extensibility of a software system. Understanding and applying this pattern can greatly improve the design and efficiency of your applications.
Feel free to experiment with the provided example and tailor it to suit your specific use cases. Happy coding! 🚀