这是否正确使用依赖注入?

时间:2011-12-21 23:46:22

标签: c# dependency-injection

我有一个服务层,可以从存储库中检索DTO。根据DTO中的属性,我需要使用两种策略之一来对DTO执行计算。我创建了一个工厂来返回适当的策略,我正在使用DI容器(Munq)来实例化对象。

public class CalculationFactory
{
    private readonly IDependencyResolver _resolver;
    public CalculationFactory(IDependencyResolver resolver)
    {
        ThrowIfNullArgument(resolver, "resolver", typeof(IDependencyResolver));
        _resolver = resolver;
    }

    public static ICalculation CreateCalculator(int serviceType)
    {
        switch (serviceType)
        {
            case 1: return _resolver.Resolve<ICalculation>("Type1");
            case 2: return _resolver.Resolve<ICalculation>("Type2");
            default: return _resolver.Resolve<ICalculation>("InvalidType");
        }
    }
}

这要求我在实例化工厂时传入依赖项解析器,以便它可以用于解析/实例化要使用的相应计算。这是正确的方法吗?如果我想添加一种新的计算类型,那么我需要更新工厂的CreateCalculator方法并注册新类型。

更新(长) 对于我害怕的建议,我并没有真正获得牵引力。我已经回到了.Net的Mark's DI副本,特别是关于重构的第6章。所以我有一个类 MeterReadings ,我需要根据运行时值使用两个计算中的一个来计算费用。我添加了一个抽象工厂,但在我的混凝土工厂中,我仍然需要 new 进行适当的计算。我觉得我错过了这一点:

public enum ServiceType
{
    Actuals = 1, CopyBlock,
}

public interface IChargeCalculator
{
    decimal CalculateCharge();
}

public interface IChargeCalculatorFactory
{
    IChargeCalculator CreateChargeCalculator(ServiceType serviceType);
}

public class MeterReading
{
    private readonly IChargeCalculatorFactory chargeCalculatorFactory;
    public MeterReading(IChargeCalculatorFactory chargeCalculatorFactory)
    {
        if (chargeCalculatorFactory == null)
            throw new ArgumentNullException("chargeCalculatorFactory");
        this.chargeCalculatorFactory = chargeCalculatorFactory;    
    }
}

public class ConcreteChargeCalculatorFactory : IChargeCalculatorFactory
{
    public IChargeCalculator CreateChargeCalculator(ServiceType serviceType)
    {
        switch (serviceType)
        {
            case ServiceType.Actuals : return new ActualsChargeCalculator();
            default: return new CopyBlockChargeCalculator();
        }
    }
}

但是在我的容器中,我可以注册不同的计算器,如果我将容器作为混凝土工厂传递,我会得到类似下面的内容(未经测试),坦率地说对我来说相当合理。任何反馈/澄清都是受欢迎的。

Container.Register<IChargeCalculator>("Actuals",
                                      c => new ActualsChargeCalculator());
Container.Register<IChargeCalculator>("CopyBlock",
                                      c => new CopyBlockChargeCalculator());
...
public enum ServiceType
{
    Actuals = 1, CopyBlock,
}

public interface IChargeCalculator
{
    decimal CalculateCharge();
}

public class MeterReading
{
    private readonly IDependencyResolver chargeCalculatorFactory;
    private ServiceType serviceType;
    public MeterReading(IDependencyResolver chargeCalculatorFactory)
    {
        if (chargeCalculatorFactory == null)
            throw new ArgumentNullException("chargeCalculatorFactory");
        this.chargeCalculatorFactory = chargeCalculatorFactory;    
    }

    public decimal Charge
    {
        get
        {
            return chargeCalculatorFactory.Resolve<IChargeCalculator>(serviceType.ToString());
        }
    }
}

2 个答案:

答案 0 :(得分:3)

是的,我会说你正在以适当的方式这样做。

虽然你写的是你需要“传入依赖解析器”,但有没有理由不能将工厂类注入到需要它的类中?然后,依赖解析器本身(对自身)依赖于依赖解析器的factorys依赖。

我希望这句话有道理。

我试图想出一个“更清洁”的解决方案,但还没有找到。类似于问题中提出的解决方案(不完全相同)Dessus链接肯定是可能的,但我真的看到只是将相同的代码移动到另一个地方。雷莫还写道,它可以在工厂类而不是工厂方法中完成。

这有点像在写一个lampda或一个帮助类之间做出决定。它主要归结为可读性,对我来说,工厂方法只是很大,并且在模块初始化程序或引导程序接缝中使它变得杂乱无章。

BTW我可以推荐Ninject,它是一个非常好的,干净的DI。另外,它的文档使用Ninja示例;)

答案 1 :(得分:0)

我相信这个问题已在这里得到解答,建议您使用元数据来绑定绑定并为每个实现创建绑定。然后使用绑定来提取元数据以选择要使用的绑定:Ninject conditional binding based on property value。 Munq可能会或可能不会这样吗?不确定。

回答这个问题的人(雷莫)是ninject的建筑师之一,知识渊博。我相信他的答案应该有很多重要性。 (我的目标是成为ninject邮件列表的订阅者,看到他回答了所有问题的一半)。