Design Pattern in Java 101 – Command Pattern (Behavioral Pattern)
By admin on Jan 26, 2008 in Behavioral, design pattern, Java, Programming
A Command pattern is an object behavioral pattern that allows us to achieve complete decoupling between the sender and the receiver. It allows you to encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests.
Here is a rewrite of the C# example provided in dofactory.com.
First define the Command interface.
public interface Command { public void execute(); public void unExecute(); }
A Calculator is a good example.
public class Calculator { private int current = 0; public void operation(char operator, int operand) { switch (operator) { case '+': current += operand; break; case '-': current -= operand; break; case '*': current *= operand; break; case '/': current /= operand; break; } System.out.println("Current value = " + current + " after " + operator + " " + operand); } }
CalculatorCommand wraps the Calculator.
public class CalculatorCommand implements Command { private char operator; private int operand; private Calculator calculator; public CalculatorCommand(Calculator calculator, char operator, int operand) { this.calculator = calculator; this.operator = operator; this.operand = operand; } public char getOperator() { return operator; } public void setOperator(char operator) { this.operator = operator; } public int getOperand() { return operand; } public void setOperand(int operand) { this.operand = operand; } public void execute() { calculator.operation(operator, operand); } public void unExecute() { calculator.operation(undo(operator), operand); } // Private helper function private char undo(char operator) { char undo; switch (operator) { case '+': undo = '-'; break; case '-': undo = '+'; break; case '*': undo = '/'; break; case '/': undo = '*'; break; default: undo = ' '; break; } return undo; } }
User invokes calculator.
import java.util.ArrayList; public class User { private Calculator calculator = new Calculator(); private ArrayList<Command> commands = new ArrayList<Command>(); private int current = 0; public void redo(int levels) { System.out.println("\n---- Redo " + levels + " levels "); // Perform redo operations for (int i = 0; i < levels; i++) { if (current < commands.size()) { Command command = commands.get(current++); command.execute(); } } } public void undo(int levels) { System.out.println("\n---- Undo " + levels + " levels "); // Perform undo operations for (int i = 0; i < levels; i++) { if (current >= 0) { Command command = commands.get(--current); command.unExecute(); } } } public void compute(char operator, int operand) { // Create command operation and execute it Command command = new CalculatorCommand( calculator, operator, operand); command.execute(); // Add command to undo list commands.add(command); current++; } }
To test it
public class TestCommandPattern { public static void main(String[] args) { // Create user and let her compute User user = new User(); user.compute('+', 100); user.compute('-', 50); user.compute('*', 10); user.compute('/', 2); // Undo 4 commands user.undo(4); // Redo 3 commands user.redo(3); } }
The output
Current value = 100 after + 100 Current value = 50 after - 50 Current value = 500 after * 10 Current value = 250 after / 2 ---- Undo 4 levels Current value = 500 after * 2 Current value = 50 after / 10 Current value = 100 after + 50 Current value = 0 after - 100 ---- Redo 3 levels Current value = 100 after + 100 Current value = 50 after - 50 Current value = 500 after * 10
Yanic | Jan 27, 2008 | Reply
Hi,
I’ve used your java design patterns sample code of the previous few posts to test my sequence diagram generator for Trace Modeler.
It worked nicely :o)
I already knew the patterns of course, but it was amazing how fast I could understand your particular examples from a single sequence diagram.
Let me know if you want the resulting images, would be a nice addition to your posts.
Best regards,
Yanic