我正在使用来自 NuGet 的 Ninject 3.0.1.10 和 ninject.extensions.factory 3.0.1.0 - 在“真实”场景中,我也将使用 ninject.extensions.conventions(而不是手动绑定 IFoo),但我想将其排除在外以尝试简化问题。
我有一个 IFoo 接口和它的多个实现,每个实现都在一个子命名空间和名为 Gen1 和 Gen2 的子文件夹下。我有一个 IFooFactory 接口,其目的是它根据指定的参数(字符串、枚举等)返回一个 IFoo。
我在这个例子中使用枚举只是为了让它更清楚 - 我最初制作了一个字符串版本,但感觉像传递一个更任意的参数(如字符串)的反对意见只会混淆这个问题。
public enum ImplementationGeneration
{
Gen1,
Gen2,
Gen3,
}
public interface IFoo
{
void DoStuff();
}
public interface IFooFactory
{
IFoo CreateFoo(ImplementationGeneration implementationGeneration);
}
namespace SomeRootNamespace.Gen1
{
public class Foo : IFoo
{
public void DoStuff()
{
Console.WriteLine("Doing Type1 stuff");
}
}
}
namespace SomeRootNamespace.Gen2
{
public class Foo : IFoo
{
public void DoStuff()
{
Console.WriteLine("Doing Type2 stuff");
}
}
}
现在,我知道让消费者“选择”这样的实现是一种理想情况下不存在的耦合形式,但恕我直言,它与 Ninject 已经支持的命名绑定具有相同级别的耦合。我想避免将属性添加到实现中,并且在工厂接口中使用 GetGen1 / GetGen2 / etc 方法非常适合这一点,因为我最终会通过某个开关将输入映射到要调用的方法来违反 OCP (或手动使用反射)
如果可能的话,我现在宁愿避免的完整/工作代码在这里:https ://gist.github.com/4549677
它使用两种方法:
- 手动工厂实现违反了 OCP 并通过了 enum 上的开关
- 使用带有 IInstanceProvider 实例的工厂扩展(子类 StandardInstanceProvider 以覆盖 GetInstance)。
第二种方法似乎“接近”让这个工作的“正确方法”,但是 1)它保持对内核的引用以完成它的工作,这可能是一个坏主意,并且 2)因为在调用期间搜索所有 IFoo 绑定时,我在 IFoo 绑定中找不到具体类型,它当前执行 GetAll,因此它实例化的实例比此场景所需的实例多 N-1 个。