Lately I seem to be working with lots of request/response stuff and I thought of creating something generic.
I have the following but I am not happy about creating multiple ifs statements and I would like to avoid them.
The idea is this:
Regardless of the request /response process them. How can I remove these if statement within my generic request Handler?
Code
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;
}
}
You can replace the GenericRequestHandler<TRequest, TResponse>
class with specialized IRequestHandler
s and have the factory keep track of all available such handlers via reflection.
Concretely, these could be the handlers:
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 };
}
}
Now, the factory, instead of just forwarding the call to the generic handler that contains the if
ugliness, will do the following:
IRequestHandler<TRequest, TResponse>
TRequest
type and the value is the handler typeThis is a possible implementation for the factory class:
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);
}
}
The complete program with working sample is available at http://ideone.com/TxRnEi.
The output is the same as the output of the original program, but now the program allows you to add new types of requests and new types of handlers and will be able to dynamically use them at run time, without you having to write the long if
/case
statements to specify when they should be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With