Injizieren von Datenverarbeitungslogik in die Klasse

10

Ich möchte einen eleganteren und wertvolleren Weg finden, um Prozessoren in den CommandProcessorDispatcherUnterricht zu bringen. Oder es kann eine andere Lösung sein (das Ziel ist es, jede Befehlsverarbeitungslogik von einer unabhängigen Klasse zu trennen). Vielleicht kann hier ein Designmuster nützlich sein.

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);
    }
}
Boo
quelle
Haben Sie sich MediatR angesehen ? Es macht im Grunde das, was Sie brauchen, und noch mehr.
Philippe
Das ist wirklich alt, daher werden klärende Fragen wahrscheinlich nicht beantwortet. Hat das etwas mit WPF oder UAP zu tun? ICommandwird mit diesen Technologien definiert und ausgiebig genutzt, daher ist es schwierig, dies von meinem Verstand zu trennen. Was ist das Endziel? Vielleicht könnte das zugrunde liegende Konzept etwas verfeinert werden.
Berin Loritsch

Antworten:

1

Ich glaube, Sie können die Dinge ein wenig vereinfachen, ohne zu viel Boilerplate, während Sie dennoch eine gewisse Sicherheit genießen .

Ein erfundenes Beispiel:

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();
    }
}

Dies macht weniger Annahmen darüber, wie die Befehlsprozessoren gespeichert werden, und erfordert keine Aktionsdelegierten, die ich in Ihrem Beispiel nicht gesehen habe. Schließlich halte ich es für vorzuziehen, den Downcast (von ICommand zu einer seiner Implementierungen) zu haben ) treten nur an einer Stelle auf.

YSharp
quelle