PTOM: Command and Conquer Your UI Coupling Problems
This post is part of the November 2008 Pablo’s Topic Of The Month (PTOM) – Design Patterns and will outline a simple Command pattern, its implementation and use.
One of the core principles of object oriented software development is the idea of Coupling, “the degree to which each program module relies on each one of the other modules” (Wikipedia). When we build software, we should strive to attain low coupling – keep the individual modules of the system as separated as possible. Of course, if there is zero coupling in a system, then the system won’t really do much for us. After all, you can’t write software that is very useful if you are not allowed to have any dependencies.
Setting Up Shop
Before we break down into the pattern, let’s consider the context of a Point Of Sale system at a coffee shop. In this system, we have a menu where your server can punch in your order with all of the options you want and produce an order that is fulfilled somewhere else. When the server starts pressing the menu items and the system begins to compile the order, there is a connection between the menu system that they are using, the various products that have been configured in the system, and the back-end ordering system. This is a rather obvious location where coupling can quickly become high – the UI, the products, and the back-end ordering system could very quickly become a spaghetti mess of tangled dependencies and tight coupling – but we don’t want that, do we?
To combat the coupling problems of this situation while still allowing dependencies, we need to introduce various forms of abstraction – simple dependencies that are not specific to any implementation, allowing us to change the implementation when we need to. In the case of a menu – be it a WinForms application, a touch screen point of sale system, or whatever else – a Command pattern is often employed to enable the system’s functionality without being directly coupled to the actual menu.
The Command Pattern
Originally outlined by the infamous “Gang of Four”, the Command Pattern is described as an object that represents an action – a command that will be executed. Within the context of a command, we have several parts that need to be accounted for.
- First and foremost, there is the actual command object – the action that is executed.
- Second, we have the command invoker – the object that depends on the commands existence, and knows how to execute the command.
- And lastly, we have the target of the invocation – the part of the system that needs to take action when the command is executed.
A Simple Implementation
To facilitate the decoupling of specific modules in our system, our command pattern implementations will be created with a naming convention that represents the objects as commands. For example, a very basic command implementation in C# can be represented as an interface such as this:
By abstracting our command into an interface, we can provide any implementation we need at runtime. This lets us select a coffee from our point of sale system and have another part of the system actually create and handle the order. A pseudo-complete implementation of a command pattern to order a cup of coffee may look something like this:
The real power of this implementation is that we have completely decoupled our menu system from any specific knowledge of the product ordering system in our coffee shop. All our menu item needs to know about is the ICommand interface. At the same time, our back-end implementation also knows about the ICommand interface – but the back-end also knows about the actual product ordering system. This allows us to create an implementation of the ICommand interface that knows how to invoke our target system. The end result is that we can independently vary the menu system for ordering coffee and our back-end product ordering system.
More Complexity And More Flexibility
Great News! Our command pattern implementations don’t have to be limited to such a rigid interface. In fact, my current project has no less than 4 different ICommand interface variations. By introducing the use of generics in C#, we can create some very flexible commands. As an example, consider the following additional interface definitions:
These new interface definitions, in combination with the original definition above, can create a very flexible and very useful set of commands in a system. By creating a “parameterized command” interface, we can provide detail in the command execution that is not available at the time the command is instantiated. And by adding another non-parameterized command with a return value, we can create a system that is able to interact in more complex ways.
With these new command interfaces in mind, let’s take another look at our RegularCoffeeCommand. Instead of hard coding the price of the coffee into the command, let’s push that knowledge off to another part of the system.
By providing an interface that accepts a parameter, we can move the knowledge of the coffee’s price out to another part of the system and provide it at runtime – a database call, a web services call, or anything else we want.
But Wait! There’s More!
As you can see, the command pattern can be very useful in helping us decouple our coffee shop’s point of sale system from the back-end product ordering system. Some very simple interface definitions can provide a lot of flexibility in how we compose our systems, as well.
What’s more – we aren’t actually limited to interfaces or base classes for abstracting our commands in .NET. The built in delegate system in .NET provides a great way to encapsulate commands with method pointers. I’ve previously talked about The Point of Delegates in .NET where I mentioned that delegates provide us with a way of delaying the execution of code. Though it’s not strictly an “object” as the command pattern describes, a delegate certainly sounds like a command pattern implementation just waiting to break out of it’s skin. In fact, I have created a few command pattern implementations using nothing more than the built in delegates in .NET, several times.
Whether you decide to use interfaces, delegates, abstract classes, or any other implementation method that you can come up with, I hope that you will think about including a command pattern implementation in your systems. It is an easy way of conquering the problems of high coupling between user interfaces and back-ends of the system.