这是对依赖注入的正确使用吗?
本文关键字:依赖 注入 | 更新日期: 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邮件列表的订阅者,看到他回答了大约一半的问题)。