The command dispatcher pattern serves to decouple the implementation of a command from its commander. The commander doesn't need to know how the execution of the command is implemented, only that the command exists.
This pattern is particularly helpful to remove input concerns from the application business. Whether the input is an HTTP request, a console command, or a message from a queue, they are all mapped to the same command, which is executed in the exact same way.
Decoupling the command from its execution makes it easy to replace or refactor the implementation, without impacting the commander. Also, because the implementation is isolated we can instantiate commands with whatever parameters and confirm results.
This pattern is also a perfect fit for domain-driven design because commands express domain problems, and their implementation can be neatly distributed across the various layers.
Finally, because it provides a unique location to execute commands, it makes it easy to implement caching and event sourcing. The dispatcher can also be decorated with before and after events for event more capable implementations.
Concepts
Three terms always associated with the command dispatcher pattern are command, dispatcher, and handler. The command is a simple DTO, usually devoid of behavior, that carries the command parameters. The dispatcher matches the command with the handler, usually using the identity of the command, its class name for example. Finally, the handler receives the command as parameter and takes care of its execution.
Disambiguation
Although similar, because the command encapsulates all the information needed to perform an action, the command dispatcher pattern is different from the command pattern, for which the command object knows about the receiver.
Although complementary, the command dispatcher pattern is also different from the command query responsibility segregation pattern, which idea is to use different models to read and write information.
Finally, the pattern differs from the event dispatcher pattern, which has many handlers, where the command dispatcher pattern matches a command with a single handler.
Example implementation
The following code samples demonstrate how the basic idea of the command dispatcher pattern could be implemented in PHP.
The dispatcher uses a handler resolver that given a command resolves the handler to use. The handler resolver usually uses a dependency injection container to instantiate the handler.
class Dispatcher {
private $handlerResolver;
public function __constructor(array $handlerResolver) {
$this->handlerResolver = $handlerResolver;
}
public function dispatch(object $command) {
$handler = $this->handlerResolver->resolve($command);
return $handler($command);
}
}
The following command can be used to create a recipe, it contains the identifier of the recipe to create and its initial payload.
final class CreateRecipe {
public $id;
public $payload;
public function __construct(string $id, array $payload) {
$this->id = $id;
$this->payload = $payload;
}
}
The following handler handles the CreateRecipe
command. It's a good idea to have the handler named after the command so it's easy to make the connection. The example code is quite shallow, but it's easy to imagine a form of validation for the payload and the use of a repository to persist the recipe.
final class CreateRecipeHandler {
// …
public function __invoke(CreateRecipe $command) {
// …
}
}
The life of a command
The life of a command could be summarised as follows:
- The application receives an input
- A command is instantiated using information from that input
- The command is passed to a dispatcher
- The dispatcher finds the handler for that command
- The command is passed to the handler
- The handler executes that command
- A result is returned (depending on the strictness of the implementation)
Testing
Because when using the command dispatcher pattern the input is decoupled from the execution, it's easy to test the implementation in isolation, without having to deal with the particular logic of a controller/console/consumer. Also, because it's very easy to instantiate a command, many cases can be checked to fully cover the implementation.
Handlers are usually quite small, and rely on multiple services for their execution. Often, these services are mocked to handle different cases.
The following example demonstrates how to test a DeleteRecipeHandler
:
final class DeleteRecipeHandler {
private $repository;
public function __construct(RecipeRepository $repository) {
$this->repository = $repository;
}
public function __invoke(DeleteRecipe $command): void {
$this->repository->delete($command->id);
}
}
class DeleteRecipeHandlerTest extends TestCase {
public function testHandler() {
$command = new DeleteRecipe($id = uniqid());
$repository = $this->prophesize(RecipeRepository::class);
$repository->delete($id)->shouldBeCalled();
$handler = new DeleteEntityHandler($repository->reveal());
$handler($command);
}
}
Once all the corner cases of the handler are tested, the integration test can simply check that executing a command yields the expected result.
The following example demonstrates how a command is used
class RecipeIntegrationTest extends TestCase {
// ...
public function testDelete() {
$id = $this->fixtures['recipe']->getId();
$command = new DeleteRecipe($id);
$this->dispatchCommand($command);
$this-assertFalse($this->repository->exists($id));
}
}
The Command Dispatcher pattern and DDD
The command dispatcher pattern is a perfect fit for domain-driven design because commands express domain problems such as "create a recipe", "rename a recipe", "publish a recipe".
Commands are defined in the application layer, handlers in the domain layer, the services they use in the infrastructure layer, and input/output adaptors are defined in the presentation layer.
The following classes could be used to create a recipe:
Application\Command\CreateRecipe
Application\Domain\Recipe\Handler\CreateRecipeHandler
Application\Domain\Recipe\RecipeRepository
(interface)Application\Infrastructure\Persistance\Repository\RecipeRepository
(implementation)Presentation\HTTP\Action\CreateRecipeAction
Advanced usage of the Command Dispatcher pattern
Implementing CQS
Because the core idea of the command dispatcher pattern is foremost execution decoupling, the same idea can be used to implement a query dispatcher. Having different dispatchers for queries and commands allows for specific logic to be implemented, like caching for instance.
Implementing caching
With a query dispatcher—variant of the command dispatcher—firing events before and after the query dispatching, and because a command (or query) has all the information required to perform a query, it's very simple to implement a caching layer. The before event can be used to provide a cached response, while the after event can be used to refresh the cache. Finally, the command can be used as cache key.
Implementing event sourcing
Event sourcing ensures that all changes to application state are stored as a sequence of events. Not just can we query these events, we can also use the event log to reconstruct past states, and as a foundation to automatically adjust the state to cope with retroactive changes. Because commands have all the information required for their execution, they are the perfect building blocks for event sourcing. They can be stored in a log and replayed later by passing in sequence to the command dispatcher.
Implementing restrictions
By emitting a before event or by decorating the command dispatcher one can implement restrictions. For instance, an HTTP controller could use a decorated command dispatcher that would require a user token and check its scope before actually dispatching the command.
tl;rd
Because it decouples the command from its execution, the command dispatcher pattern increases the flexibility of applications by enabling their services to be changed at any point in time without having to modify the application itself. It removes input concerns and facilitate testing. It enables advanced implementations such as response caching or event sourcing.
References
- Command pattern – wikipedia.org
- Paramore's Brighter – brightercommand.github.io
- The Command Dispatcher Pattern – hillside.net
- Commands, Command Handlers and Command Dispatcher – weblogs.asp.net
- Command Buses Demystified: A Look at the Tactician Package – sitepoint.com
- Event Dispatcher pattern – symfony.com
- Command Query Responsibility Segregation pattern – martinfowler.com
- Event Sourcing – martinfowler.com
- Domain-driven design – wikipedia.org