2014-05-17 1 views
5

저는 클라이언트가 다양한 유형의 명령을 서버에 보내고 구체적인 결과를 얻을 수있는 간단한 클라이언트 - 서버 솔루션을 개발 중입니다. 명령은 다른 특성을 가질 수 있습니다. 내가 원하는 것은 특정 명령 처리기가 처리하는 명령 유형에 따라 선택할 수있는 아키텍처입니다.캐스팅을 더 나은 패턴으로 바꿉니다.

public interface ICommand 
{ 
} 

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

public class CommandB: ICommand 
{ 
} 

각 명령은 명령을 처리하고 결과를 반환 할 책임이 자신의 CommandHandler을 가지고 다음과 같이 나는 기본 인프라를 만들었습니다.

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

가 나는 또한 그 결과 적절한 핸들러를 선택하고 반환에 대한 책임 클래스 생성 : 그들은 모두 CommandHandlerBaseClass에서 상속 내가 CommandHandlerBase 클래스에 캐스팅 좋아하지 않는

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

을,하지만 난 찾을 수 없습니다 그것을 피할 수있는 모든 패턴. 아래에 표시된 것처럼 일반 인터페이스를 만들 수 있지만 ReplyCreator에서 특정 처리기를 등록하고 선택하는 방법은 무엇입니까? 다음과 같이 서버에서받은

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

명령은 Json.net으로 직렬화 :

JsonConvert.SerializeObject(new CommandA(), new JsonSerializerSettings 
    { 
     TypeNameHandling = TypeNameHandling.All 
    };) 

그래서 나는 결국 콘크리트 명령으로 직렬화 적합한 핸들러에 의해 처리 될 필요가 문자열을받을 수 있습니다. 그러한 시나리오에서 캐스트를 피할 수있는 방법이 있습니까? IoC 라이브러리로 StructureMap을 사용합니다.

답변

3

왜이 캐스트를 피하려고합니까? 지금 내 마음에 오는 모든 해결 방법은 이보다 더 좋을 수 없습니다.

나는 이런 목적으로 as 키워드를 사용하지 않을 것입니다. 드문 유형이 처리기로 전달 될 때 자동으로 실패합니다. 이와 같은 경우에는 예외가 즉시 던져지기를 원합니다. 나중에 코드의 어딘가가 아닙니다.

+2

동의. 'Handle (TCommand로서의 명령)'대신'Handle ((TCommand) 명령)'을 말해야합니다. – Timwi

+0

@ SoftwareFactor 필자는 주물과 함께 살 수 있지만 최근에 비슷한 패턴을 여러 번 사용했음을 깨달았고 다른 것으로 대체 될 수 있다면 호기심을 자극했습니다. 그리고 당신은 rigth, 나는이 경우 '로'사용해서는 안됩니다. –