The Command pattern works really nicely in combination with a IoC container and DI framework that I have talked about before on this blog.
Often it is desirable for a command to take a context or state. A command should only have one method and should only have one role (single responsibility). The interface for a command could look like so:
public interface ICommand<T>So our context here is a generic and is defined when the command is registered with the container.
{
void Execute(T context);
}
So imagine we have a CRM system that when a customer is registered, we want to send that customer an email to confirm he/she has been setup correctly. You might have a domain model in this case that raises an event that is caught on the middle tier. When this occurs, instead of baking that code into the presenter/controller/business class, you abstract it out into a command. This not only makes your system more readable/maintainable but makes it easier to test too.
So in this case you could have a context class that contains the state such as the Customer domain object like so:
public class EmailCustomerConfirmationContextOur command might look something like the following:
{
public EmailCustomerConfirmationContext(Customer customer)
{
Customer = customer;
}
public Customer Customer{get; private set;}
}
public class EmailCustomerConfirmationCommand : ICommand<EmailCustomerConfirmationContext>Registering the command with the container (Compact Container - see previous posts on using this container) would look something like the following:
{
private IEmailAdapter _emailAdapter;
public EmailCustomerConfirmationCommand(IEmailAdapter emailAdapter)
{
//inject dependencies here.
_emailAdapter = emailAdapter;
}
public void Execute(EmailCustomerConfirmationContext context)
{
_emailAdapter.Send(context.Customer);
}
}
container.AddComponent<ICommand<EmailCustomerConfirmationContext>, EmailCustomerConfirmationCommand>();
Very clean approach. Of course the more dependencies you add to the command, the more complex it will become which means harder to test. So sometimes commands can become over complex. Bear this in mind when adopting this pattern.
Executing the command could look something like the following(assuming you are using the service locator):
var command = ServiceLocator.Current.GetInstance<ICommand<TContext>>();In terms of handling errors etc, this could be handled via events using some sort of event aggregator pattern or the context itself to pass back data so the middle tier can act accordingly.
if (!command.IsNull())
{
command.Execute(context);
}