The Command Pattern is well-know pattern in the OO community. Originally described in the Gang of Four book there have been multiple variants over time (e.g. http://www.javaworld.com/javaworld/javatips/jw-javatip68.html). The main characteristics of the Command pattern are:
- separates the Client of a function from the Receiver through Commands. This separation provides the flexibility to extend independently the client and the receiver;
- the Command is a first class entity that can be manipulated outside the client or receiver. This allows to create new commands from the existing ones through inheritance, group multiple commands in one and add transaction capabilities. The Command is a reification of the method invocation by the client on the receiver.
The original command pattern is powerful in itself, but working with it in multiple projects I found some limitations:
- the Command object knows (i.e. is coupled with) the Receiver in order to invoke the method. That means that the Client, which builds the Commands is also aware of the Receiver (even if not all the details). This is against the original intent of the pattern which is to decouple the client from the receiver;
- in most cases the Client is interested in the results of executing a Command. Only rarely a client has a “send-and-forget” behaviour. There are ways to pass back the results to the client for example by having a “shared” context between the client and the receiver. This solution creates a hidden dependency. A better option is for the client to register for command execution updates through the Command;
- often a Command invokes multiple Receivers in the same execution.
The article is about extensions to the Command Pattern to avoid these limitations.
The first extension is to use a generic CompositeReceiver which
contains a map with the entities that need to be manipulated through commands. The positive aspects are:
- it is possible to write commands that involve several receivers;
- when the client creates the command, it sets this generic receiver in all Commands. The Command implementation will decide which objects to use.
The negative consequences are:
- the Commands have to know the named objects stored in the Composite Receiver and cast to specific classes to access them
- some dependencies between Command and Receivers are discovered only when the command is executed, not when it is created. For example, if a required concrete Receiver is not in the CompositeReceiver this will only be found at the execution time, not at creation time.
Next, instead of the Client creating directly the receivers in the CompositeReceiver,
it will invoke commands that create the receivers. This way:
- the client is more decoupled from the receiver,
- more functionality is moved from the client into Commands.
As the number of commands grows, either because of business requirements or because of receiver-factories, rather building ad-hoc Commands the Client uses a Command Factory. In this new class command-types are registered by a name. The factory method (createCommand) instantiates the Command class and sets the parameters.
Another extension is to allow the client, or other components, to register
for notifications. For this we are using the Observer Pattern: applications interested in the notifications implement the interface CommandNotificationsHandler. Instead of passing the Notification Handlers to each command invocation, the handlers are registered in the CompositeReceiver. To make more convenient to send notification, the concrete implementations of the Command interface implement helper methods: info, warn, error, upgradeProgress, updateStatus. These helper methods are called during the execution of the command and send notifications to the registered listeners.
As seen in the previous extension, the CompositeReceiver is used beyond the initial intent of the Receiver as defined in the GoF version. It also possible to go further and keep in this object configuration information that is used during the execution of the command. To show this extended role, this class was renamed to CommandContext.
All the extensions consist in several new interfaces, abstract and concrete classes. They have to be “wired” together. In its simplest form, these entities form a Shell – a class that reads the commands from the command line and executes them, being very flexible on how to add new Commands.More complex applications, such as Swing-based will manage them differently. I is possible to also use dependency injection frameworks like Spring and Guice.
The package that contains these extensions is small but can be used to build flexible and robust applications. The source code and an example of how to use this design is available at http://www.integrationspace.com/repository/intspc/1.0/shell-1.0-src.zip.
No Comments
No comments yet.