7

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. Thank you.

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);
    }
}
  • Did you give a look at MediatR ? It basically does what you need, and some more. – Philippe Oct 5 '16 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. – Berin Loritsch Dec 29 '17 at 13:20
0

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.

-1

With focus on:

[...]or it can be another one solution (the goal is separate each command processing logic to independent class)

using Factory can make things pretty simple:

public interface ICommand { }
public class StartCommand : ICommand { }
public class StopCommand : ICommand { }

public interface ICommandProcessor
{
    void Process(ICommand command);
}

public class StartCommandProcessor : ICommandProcessor
{
    public void Process(ICommand command) { }
}

public class StopCommandProcessor : ICommandProcessor
{
    public void Process(ICommand command) { }
}

public class UnknownCommandProcessor : ICommandProcessor
{
    public void Process(ICommand command) { }
}

public class CommandProcessorDispatcher
{
    public void Process(ICommand command)
    {
        var processor = CommandProcessorFactory.GetCommandProcessor(command);
        processor.Process(command);
    }
}

public static class CommandProcessorFactory
{
    public static ICommandProcessor GetCommandProcessor(ICommand command)
    {
        if (command is StartCommand)
            return new StartCommandProcessor();
        else if (command is StopCommand)
            return new StopCommandProcessor();
        else
            return new UnknownCommandProcessor();
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var dispatcher = new CommandProcessorDispatcher();            
        dispatcher.Process(new StartCommand());
        dispatcher.Process(new StopCommand());
        Console.ReadLine();
    }
}

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.