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);
}
}
2
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.