用更好的图案替换铸件

syn*_*ror 5 c# design-patterns casting

我正在研究简单的客户端 - 服务器解决方案,客户端可以向服务器发送不同类型的命令并获得特定结果.命令可以具有不同的属性.我想要的是一种体系结构,可以根据它处理的命令类型选择特定的命令处理程序.我创建了基本的基础架构如下:

public interface ICommand
{
}

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

public class CommandB: ICommand
{
}
Run Code Online (Sandbox Code Playgroud)

每个命令都有自己的CommandHandler,负责处理命令和返回结果.它们都继承自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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我还创建了一个类,负责选择合适的处理程序并返回结果:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢在CommandHandlerBase类中进行强制转换,但我找不到任何模式来避免它.我可以创建一个如下所示的通用接口,但是如何在ReplyCreator中注册并选择一个特定的处理程序呢?

public interface ICommandHandler<TCommand>
    where TCommand : ICommand
{
    bool CanHandle(TCommand command);
    IReply Handle(TCommand command);
}
Run Code Online (Sandbox Code Playgroud)

服务器中收到的命令使用Json.net序列化,如下所示:

JsonConvert.SerializeObject(new CommandA(), new JsonSerializerSettings
    {
        TypeNameHandling = TypeNameHandling.All
    };)
Run Code Online (Sandbox Code Playgroud)

所以我收到一个字符串,最终需要反序列化为具体命令并由合适的处理程序处理.在这种情况下,有没有办法避免演员阵容?我使用StructureMap作为我的IoC库.

Sof*_*tor 3

你为什么要试图避免这个演员阵容?我现在想到的任何解决方法都不会比这更好。

我只是避免as为此目的使用关键字。在极少数情况下,当错误的类型传递给处理程序时,它会默默地失败。在这种情况下,您希望立即抛出异常,而不是稍后在代码中的某个地方抛出异常。

  • 同意。它应该说“Handle((TCommand) command)”,而不是“Handle(command as TCommand)”。 (2认同)