10

I want find more elegant and appreciate way to inject processors into CommandProcessorDispatcher class. Or it can be another one solution (the goal is separate each command processing logic to independent class). Maybe some design pattern can be useful here.

public interface ICommand { }
public class StartCommand : ICommand { }
public class StopCommand : ICommand { }
public interface ICommandProcessor<in T> where T : ICommand
{
 void Process(T command);
}
public class StartCommandProcessor : ICommandProcessor<StartCommand>
{
 public void Process(StartCommand command) { }
}
public class StopCommandProcessor : ICommandProcessor<StopCommand>
{
 public void Process(StopCommand command) { }
}
public interface ICommandProcessorDispatcher
{
 void Process(ICommand command);
}
public class CommandProcessorDispatcher : ICommandProcessorDispatcher
{
 public CommandProcessorDispatcher(Dictionary<Type, Action<ICommand>> processors)
 {
 _processors = processors;
 }
 private readonly Dictionary<Type, Action<ICommand>> _processors;
 public void Process(ICommand command)
 {
 _processors[command.GetType()](command);
 }
}
internal class Program
{
 private static void Main(string[] args)
 {
 var dict = new Dictionary<Type, Action<ICommand>>
 {
 { typeof(StartCommand), x => new StartCommandProcessor().Process((StartCommand)x) },
 { typeof(StopCommand), x => new StopCommandProcessor().Process((StopCommand)x) },
 };
 var dispatcher= new CommandProcessorDispatcher(dict);
 }
}
Engineert
9291 gold badge5 silver badges18 bronze badges
asked Feb 14, 2015 at 14:40
2
  • Did you give a look at MediatR ? It basically does what you need, and some more. Commented Oct 5, 2016 at 5:51
  • This is really old, so any clarifying questions probably won't get answered. Like, does this have anything to do with WPF or UAP? ICommand is defined with those technologies and used extensively, so it's hard to divorce that from my mind. What is the end goal? Perhaps the underlying concept could use some refining. Commented Dec 29, 2017 at 13:20

1 Answer 1

1

I believe you can simplify things a bit, without too much boilerplate, while still enjoying some type safety.

A contrived example:

public interface ICommand
{
}
#region Friends
public abstract class CommandProcessor
{
 internal abstract void Process(ICommand command);
 public abstract Type CommandType { get; }
}
public abstract class CommandProcessor<TCommand> : CommandProcessor
 where TCommand : ICommand
{
 internal override void Process(ICommand command)
 {
 Process((TCommand)command);
 }
 protected abstract void Process(TCommand command);
 public override Type CommandType { get { return typeof(TCommand); } }
}
public class CommandProcessorDispatcher
{
 public CommandProcessorDispatcher(IEnumerable<CommandProcessor> processors)
 {
 Processors = processors;
 }
 public void Process(ICommand command)
 {
 var found =
 Processors.
 FirstOrDefault
 (
 processor => processor.CommandType == command.GetType()
 );
 if (found == null)
 {
 throw new InvalidOperationException("no suitable processor found");
 }
 found.Process(command);
 }
 // (may just be protected only, depending on requirements)
 public IEnumerable<CommandProcessor> Processors { get; protected set; }
}
#endregion
public class StartCommand : ICommand
{
 public override string ToString()
 {
 return StartId.ToString();
 }
 public int StartId { get; set; }
}
public class StopCommand : ICommand
{
 public override string ToString()
 {
 return StopId.ToString();
 }
 public int StopId { get; set; }
}
public class StartCommandProcessor : CommandProcessor<StartCommand>
{
 protected override void Process(StartCommand command)
 {
 Console.WriteLine("START : " + command);
 }
}
public class EndCommandProcessor : CommandProcessor<StopCommand>
{
 protected override void Process(StopCommand command)
 {
 Console.WriteLine("STOP : " + command);
 }
}
class Program
{
 public static void Main(string[] args)
 {
 var dispatcher =
 new CommandProcessorDispatcher
 (
 new CommandProcessor[]
 {
 new StartCommandProcessor(),
 new EndCommandProcessor()
 }
 );
 var start = new StartCommand { StartId = 123 };
 var stop = new StopCommand { StopId = 456 };
 dispatcher.Process(start);
 dispatcher.Process(stop);
 Console.ReadKey();
 }
}

This makes less assumptions on how the command processors are stored, and doesn't require Action delegates, which I missed to see the purpose in your example -- finally, I think it's preferable to have the downcast (from ICommand to one of its implementations) occur at one location, only.

Robert Harvey
201k55 gold badges469 silver badges682 bronze badges
answered Oct 4, 2016 at 22:30

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.