改进此通用请求响应模式

时间:2012-11-04 11:47:13

标签: c# design-patterns

最近我似乎正在处理大量的请求/响应内容,并且我想创建一些通用的东西。

我有以下内容,但我不满意创建多个ifs语句,我想避免使用它们。

这个想法是这样的:

无论请求/响应过程如何。 如何在我的通用请求处理程序中删除这些if语句?

代码

class Program
{
    private static void Main()
    {
        IRequestResponseFactory factory = new RequestResponseFactory();

        var customerRequest = new CustomerRequest { Name = "Joe", Surname = "Bloggs" };
        var customerResponse = factory.ProcessRequest<CustomerRequest, CustomerResponse>(customerRequest);

        var billRequest = new BillRequest() { Amount = 100m };
        var billResponse = factory.ProcessRequest<BillRequest, BillResponse>(billRequest);

        Console.WriteLine(billResponse.Success);
        Console.WriteLine(customerResponse.Success);
        Console.ReadKey();

    }
}


public class CustomerRequest : IRequestData<CustomerResponse>
{
    public string Name { get; set; }
    public string Surname { get; set; }
}

public class CustomerResponse
{
    public bool Success { get; set; }
}
public class BillRequest : IRequestData<BillResponse>
{
    public decimal Amount { get; set; }
}
public class BillResponse
{
    public bool Success { get; set; }
}
public interface IRequestData<TResponse>
{
}

public interface IRequestHandler<TRequest, TResponse> where TRequest : IRequestData<TResponse>
{
    TResponse ProcessRequest(TRequest request);
}

public interface IRequestResponseFactory
{
    TResponse ProcessRequest<TRequest, TResponse>(TRequest request) where TRequest : IRequestData<TResponse>;
}
class RequestResponseFactory : IRequestResponseFactory
{
    public TResponse ProcessRequest<TRequest, TResponse>(TRequest request) where TRequest : IRequestData<TResponse>
    {
        var handler = new GenericRequestHandler<TRequest, TResponse>();
        TResponse response = handler.ProcessRequest(request);
        return response;
    }
}
public class GenericRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse> where TRequest : IRequestData<TResponse>
{
    public TResponse ProcessRequest(TRequest request)
    {
        var response = default(TResponse);

        //How do I avoid this if statements????

        if (request is IRequestData<CustomerResponse>)
        {
            var tempResponse = new CustomerResponse { Success = true };
            response = (TResponse)Convert.ChangeType(tempResponse, typeof(TResponse));
            return response;
        }
        if (request is IRequestData<BillResponse>)
        {
            var tempResponse = new BillResponse { Success = false };
            response = (TResponse)Convert.ChangeType(tempResponse, typeof(TResponse));
            return response;
        }
        return response;
    }
}

1 个答案:

答案 0 :(得分:7)

您可以使用专门的GenericRequestHandler<TRequest, TResponse>替换IRequestHandler类,让工厂通过反射跟踪所有可用的处理程序。

具体而言,这些可能是处理程序:

public class CustomerRequestHandler : IRequestHandler<CustomerRequest, CustomerResponse>
{
    public CustomerResponse ProcessRequest(CustomerRequest request)
    {
        return new CustomerResponse { Success = true };
    }
}

public class BillRequestHandler : IRequestHandler<BillRequest, BillResponse>
{
    public BillResponse ProcessRequest(BillRequest request)
    {
        return new BillResponse { Success = false };
    }
}

现在,工厂将执行以下操作,而不是仅将调用转发到包含if丑陋的通用处理程序:

  • 通过扫描当前程序集(以及可能还有其他程序集)来初始化自身,以实现IRequestHandler<TRequest, TResponse>
  • 的类型
  • 将构建一个处理程序类型的字典,其中键是TRequest类型,值是处理程序类型
  • 在任何传入请求中,它检查处理程序列表以查看是否可以处理该特定类型,并且:
    • 将工作委托给可用的处理程序
    • 如果找不到合适的处理程序,
    • 会抛出异常

这是工厂类的可能实现:

class RequestResponseFactory : IRequestResponseFactory
{
    private readonly Dictionary<Type, Type> _requestHandlerTypes;

    public RequestResponseFactory()
    {
        _requestHandlerTypes =
            typeof(RequestResponseFactory).Assembly.GetTypes()
                .Where(t => !t.IsAbstract)
                .Select(t => new
                {
                    HandlerType = t,
                    RequestType = GetHandledRequestType(t)
                })
                .Where(x => x.RequestType != null)
                .ToDictionary(
                    x => x.RequestType,
                    x => x.HandlerType
                );
    }

    private static Type GetHandledRequestType(Type type)
    {
        var handlerInterface = type.GetInterfaces()
            .FirstOrDefault(i =>
                i.IsGenericType &&
                i.GetGenericTypeDefinition() == typeof(IRequestHandler<,>));

        return handlerInterface == null ? null : handlerInterface.GetGenericArguments()[0];
    }

    public TResponse ProcessRequest<TRequest, TResponse>(TRequest request) where TRequest : IRequestData<TResponse>
    {
        if (!_requestHandlerTypes.ContainsKey(typeof(TRequest)))
            throw new ApplicationException("No handler registered for type: " + typeof(TRequest).FullName);

        var handlerType = _requestHandlerTypes[typeof(TRequest)];

        var handler = (IRequestHandler<TRequest, TResponse>)Activator.CreateInstance(handlerType);

        return handler.ProcessRequest(request);
    }
}

包含工作样本的完整程序位于http://ideone.com/TxRnEi

输出与原始程序的输出相同,但现在程序允许您添加新类型的请求和新类型的处理程序,并且能够在运行时动态使用它们,而无需编写长if / case语句,用于指定何时使用它们。