blob: 3d9ea1209cac9761b80da484a82c60fa582eb251 [file] [log] [blame]
----
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/tapestry5/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.