9

最近我似乎在处理很多请求/响应的东西,我想创建一些通用的东西。

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

这个想法是这样的:

无论请求/响应如何处理它们。如何在我的通用请求处理程序中删除这些 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;
    }
}
4

1 回答 1

8

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

具体来说,这些可能是处理程序:

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声明来指定何时应该使用它们。

于 2012-11-04T15:10:30.367 回答