【发布时间】:2016-07-12 03:04:35
【问题描述】:
在一个具体的例子中,我对依赖注入的实现感到困惑。
假设我们有一个 SomeClass 类,它具有 IClassX 类型的依赖项。
public class SomeClass
{
public SomeClass(IClassX dependency){...}
}
IClassX接口具体实现的创建依赖于运行时参数N。
使用给定的构造函数,我无法配置 DI 容器(使用 Unity),因为我不知道在运行时将使用 IClassX 的哪个实现。 Mark Seemann 在他的书 Dependency Injection In .Net 中建议我们应该使用抽象工厂作为注入参数。
现在我们有了 SomeAbstractFactory,它根据运行时参数 runTimeParam 返回 IClassX 的实现。
public class SomeAbstractFactory
{
public SomeAbstractFactory(){ }
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return new ClassX1();
case 2: return new ClassX2();
default : return new ClassDefault();
}
}
}
SomeClass 现在接受 ISomeAbstractFactory 作为注入参数:
public class SomeClass
{
public SomeClass(ISomeAbstractFactory someAbstractfactory){...}
}
这很好。我们只有一个组合根,用于创建对象图。我们配置 Unity 容器以将 SomeAbstractFactory 注入 SomeClass。
但是,我们假设 ClassX1 和 ClassX2 类有自己的依赖关系:
public class ClassX1 : IClassX
{
public ClassX1(IClassA, IClassB) {...}
}
public class ClassX2 : IClassX
{
public ClassX2(IClassA, IClassC, IClassD) {...}
}
如何解决 IClassA、IClassB、IClassC 和 IClassD 依赖关系?
1.通过 SomeAbstractFactory 构造函数注入
我们可以像这样将 IClassA、IClassB、IClassC 和 IClassD 的具体实现注入 SomeAbstractFactory:
public class SomeAbstractFactory
{
public SomeAbstractFactory(IClassA classA, IClassB classB, IClassC classC, IClassD classD)
{...}
...
}
Unity 容器将在初始组合根中使用,然后使用穷人的 DI 根据参数 runTimeParam 返回具体的 ClassX1 或 ClassX2
public class SomeAbstractFactory
{
public SomeAbstractFactory(IClassA classA, IClassB classB, IClassC classC, IClassD classD){...}
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return new ClassX1(classA, classB);
case 2: return new ClassX2(classA, classC, classD);
default : return new ClassDefault();
}
}
}
这种方法的问题:
- SomeAbstractFactory 知道不属于它的依赖项。
- 更深层次的对象图需要同时更改 SomeAbstractFactory 构造函数和类实现
- DI 容器不能用于解决依赖关系,必须使用穷人的 DI
2.显式调用 DI 容器
我们将通过使用 DI 容器来解决它们,而不是“更新”ClassX1 或 ClassX2。
public class SomeAbstractFactory
{
public SomeAbstractFactory(IUnityContainer container){...}
public IClassX GetStrategyFor(int runTimeParam)
{
switch(runTimeParam)
{
case 1: return container.Resolve<IClassX>("x1");
case 2: return container.Resolve<IClassX>("x2");
default : return container.Resolve<IClassX>("xdefault");
}
}
}
这种方法的问题:
- DI 容器被传递到 SomeAbstractFactory
- DI Resolve 方法不仅仅用于组合根(ServiceLocator 反模式)
还有其他更合适的方法吗?
【问题讨论】:
标签: c# .net dependency-injection service-locator abstract-factory