Pracuję nad prostym rozwiązaniem klient-serwer, w którym klient może wysyłać do serwera różne typy poleceń i uzyskiwać konkretne wyniki. Polecenia mogą mieć różne właściwości. Chciałbym mieć architekturę, w której można wybrać konkretną procedurę obsługi w zależności od typu komendy, którą obsługuje. Stworzyłem podstawową infrastrukturę w następujący sposób:Zastąpienie rzutowania lepszym wzorem
public interface ICommand
{
}
public class CommandA: ICommand
{
public string CustomProperty { get; set; }
}
public class CommandB: ICommand
{
}
Każde polecenie ma własny CommandHandler, który jest odpowiedzialny za obsługę polecenia i zwracanie wyniku. Wszystkie one dziedziczą 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;
}
}
ja też stworzył klasę odpowiedzialną za wybór odpowiedniej obsługi i powrocie wynik:
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);
}
}
Nie lubię odlewania w klasie CommandHandlerBase, ale nie mogę znaleźć wszelkie wzorce, aby tego uniknąć. Mogę stworzyć ogólny interfejs, jak pokazano poniżej, ale jak zarejestrować się i wybrać konkretny program obsługi w ReplyCreator?
public interface ICommandHandler<TCommand>
where TCommand : ICommand
{
bool CanHandle(TCommand command);
IReply Handle(TCommand command);
}
Komendy otrzymane w serwerze są szeregowane z Json.NET następująco:
JsonConvert.SerializeObject(new CommandA(), new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};)
Więc otrzymać ciąg, który w końcu trzeba być rozszeregować pod dowództwem betonu i obsługiwane za pomocą odpowiedniego uchwytu. Czy istnieje taki sposób unikania rzutów w takim scenariuszu? Używam StructureMap jako mojej biblioteki IoC.
Uzgodnione. Zamiast 'Handle (polecenie jako TCommand)' powinno brzmieć polecenie 'Handle ((TCommand))'. – Timwi
@SoftwareFactor Mogę na pewno żyć z castingiem, ale zdałem sobie sprawę, że ostatnio użyłem tego samego wzoru kilka razy i byłem ciekawy, czy można go zastąpić czymś innym, może lepszym. I jesteś grzeczny, nie powinienem używać "jak" w tym przypadku. –