2014-05-17 9 views
5

Ich arbeite an einfachen Client-Server-Lösung, wo Client verschiedene Arten von Befehlen an den Server senden und bestimmte Ergebnisse erhalten kann. Befehle können unterschiedliche Eigenschaften haben. Was ich gerne hätte, wäre eine Architektur, in der ein bestimmter Befehls-Handler basierend auf dem Typ des befehlten Befehls ausgewählt werden könnte. Ich habe grundlegende Infrastruktur wie folgt:Ersetzen Casting mit besseren Muster

public interface ICommand 
{ 
} 

public class CommandA: ICommand 
{ 
    public string CustomProperty { get; set; } 
} 

public class CommandB: ICommand 
{ 
} 

Jeder Befehl seine eigene Command hat, die für den Umgang mit dem Befehl und der Rückkehr Ergebnis verantwortlich ist. Sie alle erben von CommandHandlerBaseClass:

public interface ICommandHandler 
{ 
    bool CanHandle(ICommand command); 
    IReply Handle(ICommand command); 
} 

public abstract class CommandHandlerBase<TCommand> : ICommandHandler 
    where TCommand : class, ICommand 
{ 
    public bool CanHandle(ICommand command) 
    { 
     return command is TCommand; 
    } 

    public IReply Handle(ICommand command) 
    { 
     return Handle(command as TCommand); 
    } 

    public abstract IReply Handle(TCommand command); 
} 

// Specific handler 
public class CommandAHandler : CommandHandlerBase<CommandA> 
{ 
    public override IReply Handle(CommandA command) 
    { 
     //handling command and returning result 
     return null; 
    } 
} 

Ich habe auch eine Klasse verantwortlich für geeignete Handler Auswahl und Zurückkehren Ergebnis:

public interface IReplyCreator 
{ 
    IReply GetReply(ICommand command); 
} 

public class ReplyCreator : IReplyCreator 
{ 
    private readonly IEnumerable<ICommandHandler> _commandHandlers; 

    public ReplyCreator(IEnumerable<ICommandHandler> commandHandlers) 
    { 
     _commandHandlers = commandHandlers; 
    } 

    public IReply GetReply(ICommand command) 
    { 
     var commandHandler = _commandHandlers 
      .FirstOrDefault(x => x.CanHandle(command)); 

     if (commandHandler == null) 
      return null; 
     return commandHandler.Handle(command); 
    } 
} 

Ich mag es nicht in CommandHandlerBase Klasse Gießen, aber ich kann nicht finden irgendwelche Muster, um es zu vermeiden. Ich könnte eine generische Schnittstelle wie unten gezeigt erstellen, aber wie kann ich dann einen bestimmten Handler im ReplyCreator registrieren und auswählen?

public interface ICommandHandler<TCommand> 
    where TCommand : ICommand 
{ 
    bool CanHandle(TCommand command); 
    IReply Handle(TCommand command); 
} 

Die Befehle auf dem Server empfangen werden, mit Json.net serialisiert wie folgt:

mir eine Zeichenfolge So
JsonConvert.SerializeObject(new CommandA(), new JsonSerializerSettings 
    { 
     TypeNameHandling = TypeNameHandling.All 
    };) 

erhalten, die schließlich muß durch geeignete Handler deserialisiert in konkreten Befehl und behandelt werden. Gibt es in einem solchen Szenario überhaupt eine Möglichkeit, Abdrücke zu vermeiden? Ich verwende StructureMap als meine IoC-Bibliothek.

Antwort

3

Warum versuchen Sie diese Besetzung zu vermeiden? Irgendwelche Workarounds, die mir jetzt in den Sinn kommen, werden nicht schöner sein.

Ich würde einfach vermeiden, as Schlüsselwort für diesen Zweck zu verwenden. In dem unwahrscheinlichen Fall, in dem ein falscher Typ an den Handler übergeben wird, wird es unbemerkt fehlschlagen. In solchen Fällen möchten Sie, dass die Ausnahme sofort und nicht später in Ihrem Code ausgelöst wird.

+2

Einverstanden. Anstelle von 'Handle (Befehl als TCommand)' sollte es 'Handle ((TCommand) command)' heißen. – Timwi

+0

@SoftwareFactor Ich kann definitiv mit Casting leben, aber ich erkannte, dass ich in letzter Zeit ein ähnliches Muster verwendet habe und war neugierig, ob es durch etwas anderes ersetzt werden kann, vielleicht besser. Und du bist richtig, ich sollte in diesem Fall nicht "wie" verwenden. –