This week we’ll continue our exploration of design patterns and look at a very commonly used behavioural pattern, the Command pattern.
The Gang of Four book defines the Command pattern as follows:
“Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.”
Understanding the Command Pattern
Objects communicate when one object (the invoker) sends a request to another object (the receiver). The receiver processes the request in some way, and sends a response back to the invoker. The invoker and the receiver must be tightly coupled for this to happen. Ideally objects should be loosely coupled, so that changes to one component do not affect any of the other components.
The Command Pattern is a proven solution to the problem of tightly coupled invokers and receivers. Requests are encapsulated as objects that are passed around just like any other object. These request objects are called commands.
The invoker issues commands without knowing anything about the receiver. In fact, the invoker doesn’t even know what method will be called by the command. There is loose coupling between the invoker and receiver, with the command object acting as a go-between.
The command object has an execute()
method, and optionally an undo()
method. The code within the execute()
method invokes a method of the receiver, while the undo()
undoes the effects of the previous method. The command object is created by the client and passed to the invoker. The invoker issues the command when needed. The invoker doesn’t know what the actual implementations of the execute()
and undo()
methods are, and even which receiver is involved.
Command Pattern: The Problem Statement
In the previous post on the Bridge Pattern, we had created mechanised fighting units, like self-driving armoured vehicles and autonomous fighting robots. We modelled these robots and vehicles as MechanisedFightingVehicle
and MechanisedFightingRobot
s. These implemented the FightingUnit
interface. We implemented remote controls to command the units to advance, retreat and fight.
There was tight coupling between the RemoteControl
class and the FightingUnit
interface. A RemoteControl
contained a FightingUnit
object, and specific FightingUnit
methods were called by the RemoteControl
methods. There was nothing wrong with the design. It was appropriate for what we wanted to do, which was to control a FightingUnit
with a RemoteControl
.
However, if we wanted to control a number of other classes with different interfaces, this design wouldn’t work. We would want a design that promoted much looser coupling between the invoker and the receiver.
Command Pattern: Example Code
This is where the Command Pattern comes in.
We can create command classes that represent the operations that can be invoked on a receiver. We hide the receiver and method details within each concrete command class. The invoker can issue these commands without knowing anything about the receiver or the exact methods called.
Let’s start with a Command
interface:
public interface Command { public void execute(); public void undo; }
Our receivers are currently FightingUnit
s, but in the future could be anything we wanted to control: non-fighting units like medics, supply vehicles, ambulances, whatever. We don’t need to use our current RemoteControl
s. We can change the way we control units. We could let an AI engine at HeadQuarters
control the units directly. We could even send messages to them directly using the Observer pattern behind the scenes. We could use the Command pattern in any other game or application. The possibilities are endless.
Two of our concrete Command
classes follow:
public class UnitAdvanceCommand implements Command { private FightingUnit unit; public UnitAdvanceCommand(FightingUnit unit){ this.unit = unit; } @Override public void execute(){ System.out.println( "UnitAdvanceCommand.execute(): invoking advance()"); unit.advance(); } @Override public void undo(){ System.out.println( "UnitAdvanceCommand.undo(): Undoing previous action by invoking retreat()"); unit.retreat(); } } public class UnitTurnCommand implements Command { private FightingUnit unit; private int degrees; public UnitTurnCommand(FightingUnit unit, int degrees){ this.unit = unit; this.degrees = degrees; } @Override public void execute(int degrees){ System.out.println("UnitTurnCommand.execute(): turning " + degrees + " degrees."); unit.turn(degrees); } @Override public void undo(){ System.out.println("UnitTurnCommand.undo(): turning back " + degrees + " degrees."); unit.turn(-degrees); } }
This version of the RemoteControl
interface includes an undo()
method. This could possibly be implemented as a button on the remote control:
public interface RemoteControl { public void engage(); public void turn(int degrees); public void forward(); public void back(); public void undo(); }
The Command pattern version of the AbstractRemoteControl
doesn’t contain an FightingUnit
object. Rather, the client code supplies the remote control with a number of command objects, each of which contains a FightingUnit
.
public class AbstractRemoteControl implements RemoteControl { private Command forwardCommand; private Command backCommand; private Command turnCommand; private Command engageCommand; private Command previousCommand; // Setters for the supported commands public void setForwardCommand(Command forwardCommand) { this.forwardCommand = forwardCommand; } public void setTurnCommand(Command turnCommand) { this.turnCommand = turnCommand; } public void setBackCommand(Command backCommand) { this.backCommand = backCommand; } public void setEngageCommand(Command engageCommand) { this.engageCommand = engageCommand; } // Remote controls - forward, back, turn, engage @Override public void forward() { execute(forwardCommand); } @Override public void back() { execute(backCommand); } @Override public void engage() { execute(engageCommand); } @Override public void turn() { execute(turnCommand); } // Undo button @Override public void undo() { if (previousCommand == null) return; previousCommand.undo(); } // Common implementation for all controls private void execute(Command command) { if (command == null) return; command.execute(); previousCommand = command; } @Override public String toString() { return getClass().getName(); } } // end of class
We could have defined a constructor for the AbstractRemoteControl
instead of a separate setter for each command. Having four parameters for a constructor is still workable. A maximum of three to four parameters for any method is a good programming rule of thumb.
Currently the AbstractRemoteControl
class only supports one level of undo functionality with the previousCommand
field. We could build in unlimited undo operations by creating a stack of all previously executed commands, and progressively pop previous commands off the stack.
The client code creates the various RemoteControl
s and passes the commands to them. A snippet of the client code follows:
// In client code FightingUnit unit = new MechanisedFightingRobot(); // or MechanisedFightingVehicle AbstractRemoteControl remote = new BasicRemoteControl(); System.out.println(remote); remote.setForwardCommand(new UnitAdvanceCommand(unit) ); remote.setBackCommand (new UnitRetreatCommand(unit) ); remote.setTurnCommand (new UnitTurnCommand(unit, 10) ); remote.setEngageCommand (new UnitFightCommand(unit) ); System.out.println("Moving forward..."); remote.forward(); System.out.println("Moving back..."); remote.back(); System.out.println("Turning..."); remote.turn(); System.out.println("Undoing previous command"); remote.undo(); System.out.println("Engaging..."); remote.engage(); System.out.println("Undoing previous command"); remote.undo(); // more code...
Pros and Cons of the Command Pattern
Using the Command pattern has a lot of benefits:
- We can create new
RemoteControl
classes without changing any of the existingFightingUnit
classes and vice versa. - We can easily add any other controller types and receiver types.
- We can easily add different parameterised commands.
However, the Command pattern does make the code more complex and more difficult to understand. It may be overkill for a simple application.
What’s next?
In the weeks ahead, we’ll continue examining some of the more useful design patterns. Stay tuned!
As always, please share your comments and questions.
This week we’ll continue our exploration of design patterns and look at another behavioural pattern, the Interpreter pattern.
The Gang of Four book defines the Interpreter pattern as:
“Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.”
The Interpreter pattern allows us to implement a simple language to use inside an application. We define a class to represent each rule of the language (its grammar). We also implement an interpreter that operates on instances of these classes. This interpreter parses and executes the sentences of the language.
The pattern works well when we have a simple language/grammar to implement. As the grammar gets more complex, it becomes harder to maintain. With a large number of language rules, tools like parser generators are better options. These tools can interpret expressions without building abstract syntax trees. This is more efficient and can save memory space.
We very rarely use the Interpreter pattern, because as developers we hardly ever create our own languages. To use it properly, we need to know a lot about formal grammars. Formal grammars are used to create languages.
Examples
A well-known example of an interpreter is JavaScript code that runs in a web page on a browser. JavaScript is an programming language, and as such, has a grammar representation. A JavaScript interpreter uses that grammar representation to interpret and run JavaScript code. A JavaScript interpreter is built into every major browser.
SQL is another good example. An SQL interpreter is built into all relational database management systems.
In Java SE, the Interpreter pattern is used in the java.util.Pattern
and java.text.Normalizer
classes and all subclasses of java.text.Format
.
Other examples of the Interpreter pattern are the Unified Expression Language (javax.el
API) used in JSP and JSF, and the Spring Expression Language (SpEL).
Expression Hierarchy
We use the Interpreter pattern to define a class-based representation for the grammar of our language.
We create an AbstractExpression
interface (or abstract class) as the root of our class hierarchy. This is used to interpret a context. The interface defines an abstract interpret()
method that takes the context as a parameter. The context is an input stream (generally a string) containing the language sentences that must be parsed.
We then create concrete classes implementing the AbstractExpression
interface. Each class represents an expression in our language. Each expression can be either a terminal or non-terminal expression:
- Terminal expressions are the basic elements of our language. We define these with a formal grammar.
- Non-terminal expressions (also called syntactic variables) are replaced by groups of terminal symbols based on the grammar rules. The non-terminal classes are generally implemented using a composite design pattern, while the terminal expressions are leaf objects.
A non-terminal expression may have one or more AbstractExpression
s associated in it. This means it can be recursively interpreted. The interpretation process ends with a terminal expression that returns the result.
Representing each grammar rule as a class makes the language easy to implement, change or extend. We can even add extra methods to the classes (other than the interpret()
method) to support extra functionality like validation and pretty printing.
The Interpreter
We also need to create an interpreter that deals with this grammar. All of the expressions need to be processed, and from them we build an Abstract Syntax Tree (AST). The AST is just a sentence defined using the syntax of our language. This sentence is the context. The interpreter then parses the AST and produces the required output.
To interpret the language, we call the interpret()
method on each expression type. The interpret()
method is passed the context. It then matches and evaluates the expressions, and returns a result. Each expression will affect the context, change its state, and either continue the interpretation or return the result. The context is reused by all expressions during the interpretation process.
Interpreter Pattern: Design Example
Going back to our first person shooter game, we’ve already created mechanised fighting units. We’ve also developed remote controls that allow us to command them to fight and move towards specific targets. (See the post on the Command pattern).
We now decide that it will be a great new feature for players to be able to type in a string of commands that the fighting units could interpret and run. A player could even strategise an entire troop deployment and attack plan, and save this as a small text file that could be run by the command interpreter.
We will have to define a grammar for this language. At first we’ll make it fairly small, with the possibility of expanding it later. What sort of commands would we like to run? Our first thoughts may lead us to a set of commands like:
with unit #number move x, y attack if enemy found retreat if health < 20% end with
Implementation
The code implementation of this language is somewhat long for one post, so we’ll leave this post on a cliff-hanger, and continue it in next week’s post.
Stay tuned, and watch out for the conclusion of the Interpreter pattern!
As always, please share your comments and questions.