I have previously blogged about command pattern and composite pattern. I had some projects where I succesfully mixed these two together to compose a composite command. It’s a construct to have a commands hierarchy we can execute with one shot.
Why composite command?
Composite command is mix of command and composite patterns and it forms command that consists of child commands that are executed once together.
Here is the example of composite command used to save and analyze photo uploaded to web application.
It contains seven internal commands but in code we will use it as one composite command.
var command = new UploadPhotoCommand(model);
command.Execute();
Composite command is useful construct when we need to run multiple commands as one. It doesn’t matter if it is web application, web API or client-side application – it’s usable no matter of application type. What’s even better – we can build libraries for shared commands and use these all over our solution.
Don’t plan for composite commands with complex execution logic on composite level. If things get complicated there then please consider some workflow enginge instead of composite command.
To get started with composite command let’s first take a quick look at command and composite patterns.
Command pattern
By definition, as defined in famous patterns book Design Patterns: Elements of Reusable Object-Oriented Software, command pattern encapsulates a request as an object, there by letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Windows developers should know commands from WPF and UWP applications.
Composite pattern
Design patterns book also defines composite pattern. Composite pattern compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Those who have built image or media galleries should know composite pattern well. Also we can meet composite pattern in some implementations of file storage clients.
Composite command
I’m trying now to mix these two patterns to one. The goal is to keep close to existing patterns and finish with command that contains unlimited hierarchy of child commands.
Here’s the diagram showing how my composite command is built.
I start with ICommand interface. This is the interface that all commands implement.
public interface ICommand
{
void Execute();
}
Using ICommand interface I define CompositeCommand base class. I need base class because composite command has to deal with collection of child commands and their execution.
public abstract class CompositeCommand : ICommand
{
private IList<ICommand> _children = new List<ICommand>();
protected void AddChild(ICommand command)
{
_children.Add(command);
}
public void Execute()
{
foreach(var child in _children)
{
child.Execute();
}
}
}
I intentionally left out GetChild() and Remove() methods shown above in composite pattern as in practice I have never needed these methods with composite command.
But what about AddChild() method – do we need it or not? Well, it depends. If we make CompositeCommand class not abstract then we need it to be public as we can create instance of this class and we need a way to fill child commands collection. If CompositeCommand is abstract class then it’s a duty of inheriting class to fill child commands collection.
Nested composite commands. As composite command implements ICommand interface we can nest composite commands. Composite on upper level will see nested one as any other command class implementing ICommand interface.
Using composite command
As an example here’s the composite command that downloads invoices from e-commerce site, adds these to accounting system and archives downloaded files.
public class ImportInvoicesCommand : CompositeCommand
{
public ImportInvoicesCommand()
{
AddChild(new DownloadInvoicesCommand());
AddChild(new ImportInvoicesToDatabaseCommand());
AddChild(new ArchiveInvoicesCommand());
}
}
Here’s how to use this class in code.
public void ImportInvoices()
{
var command = new ImportInvoicesCommand();
command.Execute();
}
Notice that child commands are reusable and we can use it also as separate commands. We can also use them in other composite commands.
General composite command
I don’t prefer it but it’s possible to have general composite command that gets its child commands from outside. Good thing is we can combine commands to composite based on needs of given code. Bad thing is that composite commands doesn’t form new set of reusable commands.
public class CompositeCommand : ICommand
{
private IList<ICommand> _children = new List<ICommand>();
public void AddChild(ICommand command)
{
_children.Add(command);
}
public void Execute()
{
foreach(var child in _children)
{
child.Execute();
}
}
}
Using invoices import example above I can rewrite ImportInvoices() method like shown here.
public void ImportInvoices()
{
var command = new CompositeCommand();
command.AddChild(new DownloadInvoicesCommand());
command.AddChild(new ImportInvoicesToDatabaseCommand());
command.AddChild(new ArchiveInvoicesCommand());
command.Execute();
}
Here I have free hands on building composite command but when I need same kind of composite elsewhere in my code I have to duplicate the code or introduce factory method or factory class.
Ideas for extending composite command
In real life we usually don’t get away with such a simple composite. Some possible characteristics not covered here:
- Transactional commands
- Parameterized commands
- Validation before execute
- Reporting errors
I will come back to these characteristics of composite command in my future writings.
Wrapping up
Design patterns are great things and we can create mixed patterns by combining existing patterns together. This blog post focused on mixing command and composite pattern together to form composite command. Composite command works as container that contains child commands that are executed as one command. There are many practical use cases for composite commands in real-world applications and I think this pattern should belong to toolbox of every serious architect.
References
- Command pattern (Wikipedia)
- Composite pattern (Wikipedia)
View Comments (1)
Rather than .AddChild(), this seems like a perfect time to use the Builder pattern. FluentBuilder might be even better.