我有一个服务层,可以从存储库中检索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());
}
}
}
答案 0 :(得分:3)
是的,我会说你正在以适当的方式这样做。
虽然你写的是你需要“传入依赖解析器”,但有没有理由不能将工厂类注入到需要它的类中?然后,依赖解析器本身(对自身)依赖于依赖解析器的factorys依赖。
我希望这句话有道理。
我试图想出一个“更清洁”的解决方案,但还没有找到。类似于问题中提出的解决方案(不完全相同)Dessus链接肯定是可能的,但我真的看到只是将相同的代码移动到另一个地方。雷莫还写道,它可以在工厂类而不是工厂方法中完成。
这有点像在写一个lampda或一个帮助类之间做出决定。它主要归结为可读性,对我来说,工厂方法只是很大,并且在模块初始化程序或引导程序接缝中使它变得杂乱无章。
BTW我可以推荐Ninject,它是一个非常好的,干净的DI。另外,它的文档使用Ninja示例;)
答案 1 :(得分:0)
我相信这个问题已在这里得到解答,建议您使用元数据来绑定绑定并为每个实现创建绑定。然后使用绑定来提取元数据以选择要使用的绑定:Ninject conditional binding based on property value。 Munq可能会或可能不会这样吗?不确定。
回答这个问题的人(雷莫)是ninject的建筑师之一,知识渊博。我相信他的答案应该有很多重要性。 (我的目标是成为ninject邮件列表的订阅者,看到他回答了所有问题的一半)。