通用参数对象处理程序的工厂

时间:2019-11-12 20:48:29

标签: c# dependency-injection polymorphism factory factory-pattern

我有一个涉及几个无行为参数对象的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)作为服务定位器和/或不使用动力学?我发现我已经多次遇到这种情况,但是还没有想出合适的解决方案。

1 个答案:

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