it:ad:patterns:command_pattern

No renderer 'odt' found for mode 'odt'

IT:AD:Patterns:Command Pattern

The basic Command pattern is as old as the hills. Characteristics of the ICommand contract are:

  • Execute takes no argument
  • Execute returns no arguments

The rational is that it can be a serializable object representation of a method, containing all the arguments it needs to do its job, traditionally started using the object's only method – Execute():

public void interface ICommand  {
  void Execute();
}

Over the years, depending on where its being used, it has been tweeked a bit. A classic variant is the following:

public void interface IUndoableCommand  {
  public event CanExecuteChanged;
  bool CanExecute {get;}
  bool CanUnexecute {get;}
  void Execute();
  void Unexecute();
}

Note that you'll sometimes see (namely Validation), something called a Command that has an Execute method that has been stretched into returning a Result object of some kind…. But that's really no longer a Command, and simply an IFunc{TReturn} of some kind.

All that aside, an example of an implementation of the classic contract would be something like the following:

public class LogMessage : ICommand {
  ...
  public LogMessage(ITracingService tracingService, IXFerService xferService, decimal amount, Account src, Account target){...}

  public void Execute()
  {
    _xferService.XFer(src,target,amount);
    _loggingService.Log("some message...");
  }
  ...
}

Go a little further, add the Undo part, and you have a safe way to commit, and rollback every and all transactions done. Presto, safety in one move.

Note that you don't have to make every operation in your app a Command – that would be expensive overkill – so you can skip the UI stuff and just Command up Financial operations, and such.

The classic ICommand pattern is very useful…but it also was defined before IoC's became common, and the two concepts conflict.

The problem with the above example implementation of the classic ICommand pattern – when trying to use it in a DIP/IoC structured application – is of course the constructor.

This is because in the traditional definition of the Command Pattern, the Constructor is used to pass in the arguments required in order for the Execute() method to not need additional arguments when invoked later.

As you can imagine, this is not going to work…in fact it plain old mucks up the machinery of most IoC’s which are geared to push in IT:AD:Patterns:Service Pattern dependencies, not scalar arguments (at least without a lot of work).

A set of patterns that comes to the rescue is the ICommandHandler + ICommandMessage + ICommandMessageDispatcher patterns.

//The Arguments half of the contract:
public interface ICommandMessage {}

//The Action/Execute half of the contract:
public interface ICommandMessageHandler<in TCommandMessage, out TCommandResponse>
 where TCommandMessage : ICommandMessage 
 where TCommandResponse : ICommandResponse 
 {
  //Note: action is separated from command args:
  void Execute(TCommandMessage commandMessage);
 }

//The runner: 
public interface ICommandDispatcher {
  void Execute<TCommandMessage>(TCommandMessage commandMessage) 
    where TCommandMessage: ICommandMessage;
}

Ignoring the ICommandDispatcher (sometimes called ICommandBus) for a second, let’s look at what’s been defined.

What we are doing here is separating the Args required for execution from the Execution part.

This means that on one hand, the command message/data can be serialized, and on the other, the Executor / Handler can be DI’ed with services as required. Conflict solved!

We can rewrite our log command as something like:

public class XFerCommandMessage : ICommandMessage{
  public Account Src {get;set;}
  public Account Target {get;set;}
  public decimal Amount {get;set;}
}

public class XFerMessageHandler : ICommandMessageHandler<LogCommandMessage>{
  IXFerService _xferService;

  public LogCommandMessageHandler(IXFerService xferService){
    _xferService = xferService;
  }

  public void Execute(XFerCommandMessage xferCommandMessage){    _xferService.Xfer(xferCommandMessage.Src,xferCommandMessage.Target,xferComandMessage.Amount);
  }
}

This will be run using:

#!c#
public interface ICommandDispatcher {
  TCommandResponse Execute<TCommandMessage,TComandResponse>(TCommandMessage comandMessage)
   where TCommandMessage: ICommandMessage
   where TCommandResponse: ICommandResponse
}
public class CommandDispatcher : ICommandDispatcher {
  public TCommandResult Execute<TCommandMessage>(TCommandMessage commandMessage) 
    where TCommandMessage : ICommandMessage
    where TCommandResponse: ICommandResponse
    {    

    //Let the bus find the Handler appropriate
    //for the given command:
    ICommandMessageHandler<TCommandMessage> commandMessageHandler = 
    _serviceLocator.Current.GetService<ICommandMessageHandler<TCommandMessage>>();

    //and execute it (no return):
    commandMessageHandler.Execute(command);
  }
}

Et voila. Now you can do something as simple as first:

 XFerMessage xferMessage= new XFerMessage(src,target,100.00);
 CommandMessageDispatcher.Execute(xferMessage);
 //Bam! The dispatcher finds the EventHandler registered
 //in the IoC that will work with the above message,
 //invokes it Execute method, passing it the Message,
 //and bob's (Bob Martin...)'s your uncle. 

Again, take that further and the ServiceBus/ServiceDispatcher gets an Undo method as well.

Take it even further – add Memento to the solution, and you have a serializeable queue of undoable operations.

PPS: About nomenclature: Note that many developers call the above ICommandMessage ICommandData – or worse ICommand. I think both of these names are inappropriate,

For one the word Command implies execution – which an argument package obviously is not. I don’t have anything against Data…it is appropriate, but I prefer Message, as it implies the ability to cross layers and tiers, and be executed where ever the Handler is located.

Just seems more…future proof. But don’t be surprised if in many cases you see it called ICommand, that’s all.

PPPS: Finally, note that all the above contracts etc are all already defined in Projects:XActLib's XAct.Core assembly – don't go reinventing the wheel.

* vDbTkt


IT:AD:Patterns:Command


As per this post:

public interface ICommandResponse {
  bool Success {get;}
  bool Message {get;}
  IEnumerable<Exception> Exceptions {get;}
}
public interface ICommandMessage {
}
public interface ICommandMessageHandler<in TCommandMessage>
 where TCommandMessage : ICommandMessage {
  //Note: action is separated from command args:
  ICommandResult Execute(TCommandMessage commandMessage);
}
public interface ICommandDispatcher {
  ICommandResult Execute<TCommandMessage>(TCommandMessage commandMessage) 
    where TCommandMessage: ICommandMessage;
  //IEnumerable<Exception> Validate<TCommandMessage>(TCommandMessage commandMessage) 
  //where TCommandMessage : ICommandMessage;
}
  • /home/skysigal/public_html/data/pages/it/ad/patterns/command_pattern.txt
  • Last modified: 2023/11/04 03:28
  • by 127.0.0.1