The architecture of the simple command framework is - as named - simple. It comes with a couple of interfaces and some default implementation.
For each purpose you've a dedicated interface and sometimes an abstract implementation. You can pass a parameter object among the whole chain which has to fulfill the
ParameterObject interface. The
ParameterObject interface is just a marker for those objects.
The framework follows the composite pattern. You've a second interface which is a command as well but works as a container of commands. You can create chains with commands and command container as well.
For each interfaces you've default implementations which you can use for your own purposes.
AbstractDefaultChainCommand provides an empty
execute() method but an implementation of the chain of responsibility framework. The
executeAsChain() method calls the
execute() method. If there is no exception thrown it returns true. True means, the work hasn't been done and the next command should be called. If the
execute() method throws an exception, it is an indicator that the execution of the chain should be stopped. For this the
executeAsChain() method results false.
This is a good approach if the execution of the chain has to be stopped because an error has occurred. It may be a bad approach, if you want to stop because everything is fine. In this case you've to throw an exception: Everything is fine, the work is done. This is a little bit an anti-pattern but unfortunately there is no "positive exception" in Java.
DefaultCommandContainer has convenient methods to add commands to a container. Either in natural order (just add it) or via priority. If you add two commands with the same priority the first inserted command is executed first. Even the container has the same behavior as a simple command you can execute the container in the same way as a command. You can add a container in a container as well.
For bypassing parameter objects you may want to use the
GenericParameterObject interface, which provides methods to add key-value pairs into the object. An implementation of that is the
A brief description of the parts of the framework
Command: Interface for wrapping an algorithm. Everything is a command.
ChainCommand: Interface for a command which works in the second mode: Chain of Responsitibility.
ProcessCommand: Interface for a command which works in the third mode: Process Mode.
CommandContainer: Interface for grouping different
Command objects in a container. This fits the composite pattern:
CommandContainer objects have the same behavior as
Command objects. For this it is possible to add
Command objects as well as
CommandContainer in such a container.
ParameterObject: Marker interface for a parameter object.
ParameterObject objects are the glue between different commands. Because of the concept of these objects the whole framework is thread-safe and supports re-entrant algorithms.
Generic: Interface for a generic parameter object that holds a list of keys and values. A better approach is to create own type-safe parameter objects with get- and set-methods for the values (Bean convention). Because the whole framework works with generics you can instantiate each command with your own parameter object.
AbstractDefaultChainCommand: An implementation which provides a generic method for fulfilling the chain-of-responsibility pattern. Just call
executeAsChain(). All commands will be executes. If one command fails the execution is stopped.
AbstractDefaultProcessCommand: An Implementation which provides a generic method for fulfilling the process mode. Just call
executeAsProcess(). All commands will be executed in the right way.
DefaultCommandContainer: An implementation to add commands into a container. The execution of the container will execute all parts of it (either commands or command-containers). This fulfils the composite pattern. The
DefaultCommandContainer actually implements all three modes.
Default: An implementation of the
Generic interface to work with generic data in a generic data structure. This is not recommended because it is not type safe.
ChainBuilder ist an interface to build chains from different sources e.g. XML, java configured or any other. Concrete classes have to implement the
ChainBuilder which takes a Spring configuration or any other DI framework to build the actual chain.
ChainBuilder which takes an XML configuration to build the actual chain.