---- | |
Chain of Command | |
---- | |
Chain of Command | |
One of the most useful of the Gang Of Four Design Patterns is the <<command>> pattern. | |
With the command pattern, a complex process is broken down into many individual steps. The | |
steps are the <commands> in the command pattern. A key part of this is that the commands | |
are expected to implement some common interface. The commands are carefully arrainged into | |
a specific order. | |
The process operates by working down the list of commands. Each command is given a chance | |
to operate. A command can terminate the process either by throwing an exception, or by | |
returning true. | |
The return type of the command method does not have to be boolean: For object types, | |
any non-null value short-circuits the process. For numeric type, any non-zero value. | |
For void methods, only throwing an exception will short circuit the process. | |
Often, the command interface consists of a single method. When the command interface | |
has multiple methods, each can be thought of as its own chain. | |
This is a useful pattern because it makes it very easy to <extend> a given process, | |
simply by providing new commands and specifying where they fit into the overall | |
process. Most often chain of command is combined with an ordered | |
{{{configuration.html}configuration}} to define what the list of commands are (and in what | |
order they should execute). | |
ChainBuilder Service | |
Because this pattern is used so often inside Tapestry, a built-in service exists | |
to create implementations of the pattern as needed. The | |
{{{../apidocs/org/apache/tapestry/ioc/services/ChainBuilder.html}ChainBuilder}} | |
service takes care of all the work: | |
+----+ | |
public interface ChainBuilder | |
{ | |
<T> T build(Class<T> commandInterface, List<T> commands); | |
} | |
+----+ | |
All that generics parameterization just ensures that the command interface matches | |
the items in the list, and confirms that a single instance of the command interface | |
will be returned. | |
Invoking this method returns an object that encapsulates the chain of command for a | |
particular interface and a particular list of commands implementing that interface. | |
This can be used inside a service builder method. Nothing says a service builder method | |
just has to instantiate a class; it is only required to return an appropriate object. | |
We can just let the ChainBuilder service create that object. | |
+----+ | |
public static MyChainService build(List<MyChainService> commands, | |
@InjectService("ChainBuilder") | |
ChainBuilder chainBuilder) | |
{ | |
return chainBuilder.build(MyChainService.class, commands); | |
} | |
+----+ | |
Here, the behavior of the MyChainService is defined by its configuration: an ordered | |
list of MyChainService commands that are contributed by one or more modules. | |
Internally, the ChainBuilder creates a new class that implements the service interface. | |
The list of commands is converted into an array, which is used inside the service implementation | |
(for maximum efficiency). Therefore, changing the list after creating the chain | |
instance will not affect the chain instance's behavior. | |
ChainBuilder will reuse the fabricated class for any number of chains of the same | |
command interface. |