这是对依赖注入的正确使用吗?

本文关键字:依赖 注入 | 更新日期: 2023-09-27 18:18:28

我有一个从存储库检索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方法并注册新类型。

更新(长)恐怕我对这些建议并没有什么好感。我回到了Mark在。net中的DI版本,特别是关于重构的第6章。所以我有一个类 meterreads ,我需要使用基于运行时值的两个计算之一来计算收费。我添加了一个抽象工厂,但在我的具体工厂中,我仍然需要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());
        }
    }
}

这是对依赖注入的正确使用吗?

是的,我认为你的做法是正确的。

虽然你写你需要"传递依赖解析器",有一个原因,你不能有工厂类注入到类的需要吗?那么,工厂对依赖解析器的依赖应该由依赖解析器自身(对自身)进行解析。

我希望这句话是有意义的。

我试图想出一个"更干净"的解决方案,但还没有找到任何。类似于问题中建议的解决方案(并不完全相同)Dessus链接当然是可能的,但我真的认为这只是将相同的代码移动到另一个地方。Remo还写道,它可以在工厂类中完成,而不是在工厂方法中。

这有点像决定是写一个lamp还是一个helper类。这主要归结为可读性,对我来说,工厂方法太大了,把它放在模块初始化器或引导器中会显得杂乱无章。

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

我相信这里已经回答了这个问题,这里建议您对绑定使用元数据,并为每个实现创建绑定。然后使用绑定来提取元数据,以选择使用哪个绑定:根据属性值添加条件绑定。对Munq来说,这可能是可能的,也可能是不可能的?不确定。

回答这个问题的人(Remo)是ninject的架构师之一,并且非常博学。我相信他的回答应该很有分量。(我是一个ninject邮件列表的订阅者,看到他回答了大约一半的问题)。