C# – Ninject,IoC和工厂模式

我有一个控制台应用程序,我需要根据用户的输入执行某个function。 如果用户输入“function1” – >我执行function1,依此类推。

我正在尝试将此项目编写为尽可能干净且通用,我想使用IoCSOLID概念,我有点卡住了。

到目前为止我所拥有的:

public interface IFeature { String execFeature(); } 

 interface IFeatureFactory { IFeature createFeature(String input); } 

我的第一个想法只是在具体的Factory类上有一个关于用户输入的开关案例 ,并相应地创建具体的function ,但我敢打赌,有一个更好的方法来使用IoC

我读了Ninject工厂扩展,但不明白如何在我的项目中使用它。

使用IoC / Ninject进行工厂模式的最佳方法是什么?

如果你的IFeature实现没有其他依赖关系,那么使用你的方法就很好而且非常简单。
例如,假设您有2个IFeature实现 – SomeFeature和OtherFeature都具有无参数构造函数。
您建议的工厂实施将是这样的:

 public class FeatureFactory: IFeatureFactory { IFeature CreateFeature(string input) { if(input=="SomeFeature") { return new SomeFeature(); } else { return new OtherFeature (); } } } 

但是,当您的IFeature实现使用此方法拥有自己的依赖项时,您将无法使用Ninject和IoC。
例如,假设SomeFeature看起来像这样:

 public class SomeFeature : IFeature { private readonly IDependency1 _dependency1; private readonly IDependency2 _dependency2; public SomeFeature (IDependency1 dependency1, IDependency2 dependency2) { _dependency1=dependency1; _dependency2=dependency2; } string execFeature() { //Some code here... } } 

和其他特征类似……

  public class OtherFeature: IFeature { private readonly IDependency1 _dependency1; private readonly IDependency2 _dependency2; public OtherFeature(IDependency1 dependency1, IDependency2 dependency2) { _dependency1=dependency1; _dependency2=dependency2; } string execFeature() { //Some code here... } } 

现在你的工厂会变成这样的东西:

  public class FeatureFactory: IFeatureFactory { IFeature CreateFeature(string input) { if(input=="SomeFeature") { return new SomeFeature(new Dependency1Implementation(), new Dependency2Implementation()); } else { return new OtherFeature(new Dependency1Implementation(), new Dependency2Implementation()); } } } 

通过使用容器为您解决这种依赖关系,您可以使用ninject.extensions.factory的强大function。(这种依赖关系可能有自己的依赖关系,并且可能会很快变得混乱)。
正如其他提到的,您可以使用命名绑定绑定每个IFeature实现。

 Bind().To().Named("SomeFeature"); Bind().To().Named("OtherFeature"); 

当然,您也应该绑定其他依赖项

 Bind().To(); Bind().To(); 

然后使用工厂扩展将IFeatureFactory绑定到Factory。

 Bind().ToFactory(); 

您需要做的是为IFeatureFactory中的每个IFeature实现创建工厂方法,并根据Feature命名绑定将其命名为Get ….

 public interface IFeatureFactory { IFeature GetSomeFeature(); IFeature GetOtherFeature(); } 

现在ninject将为您实现(!)这个类,并知道为每个方法选择哪个实现。(不需要服务定位器….)
您可以在客户端的输入上使用switch语句来选择要调用的工厂方法,或者可以将其包装在将在其中包含switch语句的某个提供程序类中,在这两种情况下,您都不必执行“new” IFeature自己实现。
当然,如果需要和其他更复杂的事情,您可以通过工厂方法将参数传递给实现构造函数。

我建议你阅读这些以获取更多信息。

编辑
我想强调你不必为每个实现编写工厂方法,你可以对所有人使用相同的方法(有可能但更复杂)。
要做到这一点,您需要创建自定义实例提供程序来检测要实例化的实现(例如,根据工厂参数),在上面和此处的链接中有更多相关信息。

您可以使用Named Bindings 。 示例代码:

 Bind().To().Named("Feature1"); Bind().To().Named("Feature2"); 

有关更多信息

编辑

如果您不喜欢Service locator pattern ,则上述方法不适合您的情况,因为您必须使用IKernel来解析IFeature

IoC的主要思想之一是您不应该在解决方案的组件之间存在依赖关系。 因此,仅使用接口并且不使用关键字“new”创建类的新实例是一种很好的方法。 您的问题无法以简单而优雅的方式解决,因为您只能注入所有function实现的接口。

所以你有一些function和它们的实现:

 internal interface IFeature { } internal interface IFeature1 : IFeature { } internal interface IFeature2 : IFeature { } 

还有一家工厂:

 internal interface IFeatureFactory { IFeature GetInstance(string featureName); } internal class FeatureFactory : IFeatureFactory { private readonly ITypeFactory feature1; private readonly ITypeFactory feature2; private readonly Dictionary> featuresContainer; public FeatureFactory(ITypeFactory feature1, ITypeFactory feature2) { this.feature1 = feature1; this.feature2 = feature2; featuresContainer = new Dictionary> { {"Feature1", feature1}, {"Feature2", feature1} }; } public IFeature GetInstance(string featureName) { if (!featuresContainer.ContainsKey(featureName)) throw new Exception(string.Format("Can't create feature {0}", featureName)); return featuresContainer[featureName].Create(); } } 

你可以用这种方式注入所有这些东西:

  Bind().To().InSingletonScope(); Bind().To(); Bind().To(); Bind>().ToFactory(); Bind>().ToFactory(); 

主要的想法是,您只有一个function工厂实例用于应用程序,并且您存储了function的注入工厂。 因此,当您第一次访问IFeatureFactory时,Ninject将创建它的单例实例。 但是只有在调用GetInstance()方法时才会创建要素实例。

要使此代码工作,您应该添加新接口:

 public interface ITypeFactory { T Create(); } 

并安装NuGet包: https : //www.nuget.org/packages/Ninject.Extensions.Factory/