我有一个涉及几个无行为参数对象的API,每个对象都有自己的处理程序:
//some POCOs
public class CustomerChange : IChange{
public int CustomerId {get;set;}
public DateTime TimeStamp {get;set;}
}
public class SomeOtherChange : IChange{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
}
// stateless handlers that will be resolve with a DI container (Ninject in my case)
public interface IChangeHandler<TChange>{
public Handle(T change);
}
public class CustomerChangeHandler : IChangeHandler<CustomerChange>{
private readonly ICustomerRepository customerRepository;
public CustomerChangeHandler(ICustomerRepository repo){
customerRepository = repo;
}
public Handle(CustomerChange change){
customerRepository.DoStuff(change.CustomerId);
}
}
以此类推。
当在编译时知道IChange的类型时,这非常有用,但是,我遇到了需要处理未知类型的IChanges的情况。
在理想的世界中,我希望能够做以下事情:
public class ChangeHandlerFactory {
public void HandleChange(IChange change){
// get the change handler from the DI container based on the concrete type of IChange
var handlerType = typeof(IChangeHandler<>)
.MakeGenericType(change.GetType());
object handler = container.GetInstance(handlerType); //is this an acceptable way to use a DI container? I would need a dependency on IKernel in this case
handler.Handle(change); // I would need to cast the change object to the appropriate type for the handler or make handler dynamic which seems like it has the potential for hard to debug issues
}
}
我对使处理程序具有动态性的担心是,某人可能会错误地执行某项操作,并且会变得难以调试错误。
我可以让每个POCO都实现一个GetHandler方法来检索处理程序,但是这几乎使首先分离它们的整个工作变得毫无意义。
在这样的情况下获取处理程序的最佳方法是什么?有没有一种方法可以不使用我的DI容器(ninject)作为服务定位器和/或不使用动力学?我发现我已经多次遇到这种情况,但是还没有想出合适的解决方案。
答案 0 :(得分:0)
最简单的是依赖倒置。让POCO提供一个委托来获取自己的处理程序,因为它显然已经知道它是什么类型。
interface IChange
{
IChangeHandler GetHandler(Container container);
}
public class SomeOtherChange : IChange
{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
public IChangeHandler GetHandler(Container container) => container.GetInstance<SomeOtherChangeHandler>();
}
然后您可以编写一个通用处理程序映射器:
public void HandleChange(IChange change)
{
var handler = change.GetHandler(container);
//etc....
当然,这给您一个问题,一旦有了处理程序,该如何处理该处理程序。同样,您可以让POCO进行工作:
public class SomeOtherChange : IChange
{
public int AParameter {get;set;}
public string AnotherParameter {get;set;}
public DateTime TimeStamp {get;set;}
public void GetAndCallHandler(Container container)
{
var handler = container.GetInstance<SomeOtherChangeHandler>();
handler.Handle(this);
}
}