IoC和构造函数过注入反模式解析

Ste*_*ght 10 .net c# dependency-injection inversion-of-control

这个问题是Jeffery Palermo关于如何解决分支代码和依赖注入问题的结果http://jeffreypalermo.com/blog/constructor-over-injection-anti-pattern/

在他的帖子中,Jeffery有一个class(public class OrderProcessor : IOrderProcessor),在构造函数上有2个接口.一个是验证器IOrderValidatorIOrderShipper接口.他的方法代码只在IOrderValidator接口上使用方法后才会分支,从不在IOrderShipper接口上使用任何东西.

他建议创建一个工厂,调用静态方法来获取接口的委托.他正在重构的代码中创建一个新对象,这似乎是不必要的.

我想问题的关键在于我们使用IoC来构建所有对象,无论它们是否被使用. 如果您实例化一个具有2个接口的对象并且具有可以分支以不使用其中一个的代码,那么您如何处理它?

在这个例子中,我们假设_validator.Validate(order)always总是返回false,并且IOrderShipper.Ship()永远不会调用该方法.

原始代码:

public class OrderProcessor : IOrderProcessor
{
    private readonly IOrderValidator _validator;
    private readonly IOrderShipper _shipper;

    public OrderProcessor(IOrderValidator validator, IOrderShipper shipper)
    {
      _validator = validator;
      _shipper = shipper;
    }

    public SuccessResult Process(Order order)
    {
      bool isValid = _validator.Validate(order);
      if (isValid)
      {
          _shipper.Ship(order);
      }
      return CreateStatus(isValid);
    }

    private SuccessResult CreateStatus(bool isValid)
    {
        return isValid ? SuccessResult.Success : SuccessResult.Failed;
    }
}

public class OrderShipper : IOrderShipper
{
  public OrderShipper()
  {
      Thread.Sleep(TimeSpan.FromMilliseconds(777));
  }

  public void Ship(Order order)
  {
      //ship the order
  }
}
Run Code Online (Sandbox Code Playgroud)

重构代码

public class OrderProcessor : IOrderProcessor
{
    private readonly IOrderValidator _validator;

    public OrderProcessor(IOrderValidator validator)
    {
      _validator = validator;
    }

    public SuccessResult Process(Order order)
    {
      bool isValid = _validator.Validate(order);
      if (isValid)
      {
          IOrderShipper shipper = new OrderShipperFactory().GetDefault();
          shipper.Ship(order);
      }
      return CreateStatus(isValid);
    }

    private SuccessResult CreateStatus(bool isValid)
    {
        return isValid ? SuccessResult.Success : SuccessResult.Failed;
    }
}   

public class OrderShipperFactory
{
    public static Func<IOrderShipper> CreationClosure;
    public IOrderShipper GetDefault()
    {
        return CreationClosure(); //executes closure
    }
}
Run Code Online (Sandbox Code Playgroud)

这是在启动时配置此工厂的方法(ASP.NET的global.asax):

private static void ConfigureFactories()
{
    OrderShipperFactory.CreationClosure =
        () => ObjectFactory.GetInstance<IOrderShipper>();
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ann 22

我刚刚发布了Jeffrey Palermos帖子反驳.

简而言之,我们不应该让具体的实施细节影响我们的设计.这将违反建筑规模上的Liskov替代原则.

更优雅的解决方案让我们通过引入延迟加载OrderShipper来保持设计.

  • +1我同意你的反驳意见.这种反模式对我来说似乎不对,因为你的`OrderProcessor`现在依赖于`IOrderShipper`而你没有通知你的消费者. (3认同)