Command Pattern
The Command Pattern is a data-driven design pattern that belongs to the category of behavioral patterns. Requests are encapsulated in objects and passed to the invoking object. The invoking object finds the appropriate object capable of handling the command and passes the command to it for execution.
Introduction
Intent: Encapsulate a request as an object, thereby allowing parameterization of clients with different requests.
Main Solution: In software systems, the behavior requester and behavior implementer are usually tightly coupled. However, in certain scenarios, such as when actions need to be logged, undone, redone, or managed as transactions, this tightly coupled design is not suitable.
When to Use: In scenarios where actions need to be "logged, undone/redone, or managed as transactions," decoupling the behavior requester from the behavior implementer is necessary. Abstracting a set of behaviors into objects can achieve loose coupling between the two.
How to Solve: The invoker invokes the receiver to execute the command, following the sequence: invoker → command → receiver.
Key Code: Define three roles: 1. received (actual command execution object), 2. Command, 3. invoker (entry point for using command objects)
Application Example: In Struts 1, the core controller ActionServlet acts as the invoker, while model layer classes vary for different applications, serving as specific commands.
Advantages: 1. Reduces system coupling. 2. New commands can be easily added to the system.
Disadvantages: Using the command pattern may lead to an excessive number of specific command classes in some systems.
Usage Scenarios: Any situation that can be considered a command can use the command pattern, such as: 1. Each button in a GUI is a command. 2. Simulating CMD.
Considerations: If the system needs to support undo and redo operations for commands, the command pattern can be considered, as seen in its extensions.
Command Pattern Structure Diagram:
Implementation
We first create an interface Order as the command, and then create a Stock class as the request. Concrete command classes BuyStock and SellStock implement the Order interface and handle the actual command processing. A Broker class, acting as the invoking object, accepts orders and can place orders.
The Broker object uses the command pattern to determine which object executes which command based on the command type. The CommandPatternDemo class uses the Broker class to demonstrate the command pattern.
Step 1
Create a command interface.
Order.java
public interface Order {
void execute();
}
Step 2
Create a request class.
Stock.java
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+", Quantity: " + quantity +" ] sold");
}
}
Step 3
Create concrete classes that implement the Order interface.
BuyStock.java
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
SellStock.java
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}
Step 4
Create a command invoker class.
Broker.java
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List<Order> orderList = new ArrayList<Order>();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}
Step 5
Use the Broker class to accept and execute commands.
CommandPatternDemo.java
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}
Step 6
Execute the program, and the output will be:
Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold