用更好的图案替换铸件

时间:2014-05-17 06:32:24

标签: c# design-patterns casting

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

public interface ICommand
{
}

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

public class CommandB: ICommand
{
}

每个命令都有自己的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;
    }
}

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

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

我不喜欢在CommandHandlerBase类中进行转换,但是我找不到任何模式来避免它。我可以创建一个如下所示的通用接口,但是如何在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
    };)

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

1 个答案:

答案 0 :(得分:3)

你为什么试图避免这种演员?现在我想到的任何变通方法都不会比这更好。

我会避免使用as关键字来实现此目的。当错误的类型传递给处理程序时,它将在不太可能的情况下无声地失败。在这种情况下,您希望立即抛出异常,而不是在代码中的某个地方抛出异常。