我已经阅读了很多关于这个主题的内容,但是无法一直掌握它。
我正在尝试使用 Ninject.Extensions.Factory 而不是我的工厂来根据用户输入创建新对象。我想充分利用Ninject功能和IoC概念。
现在代码如下:
interface IFeatureFactory
{
IFeature createFeature(int input);
}
并
class BasicFeatureFactory : IFeatureFactory
{
public IFeature createFeature(int input)
{
switch (input)
{
case 1:
return new FirstFeature();
case 2:
return new SecondFeature();
default:
return null;
}
}
}
将来, IFeature 将具有依赖关系,因此我希望以 IoC 方式进行。
修改
消费者类 - 将 IFeatureFactory 和 IUILayer 注入 FeatureService 构造函数并使用进行解析Ninject
private IFeatureFactory featureFactory;
private IUILayer uiHandler;
public FeatureService(IFeatureFactory featureFactory, IUILayer uiHandler)
{
this.featureFactory = featureFactory;
this.uiHandler = uiHandler;
}
public void startService()
{
int userSelection = 0;
uiHandler.displayMenu();
userSelection = uiHandler.getSelection();
while (userSelection != 5)
{
IFeature feature = featureFactory.createFeature(userSelection);
if (feature != null)
{
IResult result = feature.execFeature();
uiHandler.displayResult(result);
}
else
{
uiHandler.displayErrorMessage();
}
uiHandler.displayMenu();
userSelection = uiHandler.getSelection();
}
}
和IFeature类:
public interface IFeature
{
IResult execFeature();
}
绑定:
public override void Load()
{
Bind<IFeatureFactory>().To<BasicFeatureFactory>();
Bind<IUILayer>().To<ConsoleUILayer>();
}
如何使用 Ninject.Extensions.Factory 将此工厂模式转换为 IoC ?请记住, IFeature 的创建取决于用户输入。
答案 0 :(得分:2)
对我来说,看起来你有2个选项来重构你的代码以获得ninject的全部好处。
你现在的工作方式与pure di没什么不同(它没有任何问题,在某些情况下更好),但正如你所说,你想要完全使用ninject功能。
选项一
而不是将IFeatureFactory注入FeatureService注入接口IFeatureProvider,如下所示:
public interface IFeatureProvider
{
IFeature GetFeature(int featureType);
}
现在,您的FeatureService将从此提供商而不是工厂获取所请求的功能 您将需要实现IFeatureProvider,为此您将需要另外2个接口IFirstFeatureFactory和ISecondFeatureFactory:
public interface IFirstFeatureFactory
{
IFeature CreateFirstFeature();
}
public interface ISecondFeatureFactory
{
IFeature CreateSecondFeature();
}
现在是IFeatureProvider的阻碍:
public class FeatureProvider: IFeatureProvider
{
private readonly IFirstFeatureFactory _firstFeatureFactory;
private readonly ISecondFeatureFactory _secondFeatureFactory;
public FeatureProvider(IFirstFeatureFactory firstFeatureFactory, ISecondFeatureFactory secondFeatureFactory)
{
_firstFeatureFactory=firstFeatureFactory;
_secondFeatureFactory=secondFeatureFactory;
}
public IFeautre GetFeature(int featureType)
{
switch(featureType)
{
case 1:
return _firstFeatureFactory.CreateFirstFeature();
case 2:
return _secondFeatureFactory.CreateSecondFeature();
default:
return null;
}
}
}
你要注意的是我只是将负责“新”的对象提取到另一个界面
我们不会实现两个工厂接口,因为如果我们正确绑定它,ninject将为我们做。
绑定:
Bind<IFeature>().ToFeature<FirstFeature>().NamedLikeFactoryMethod((IFirstFeatureFactory o) => o.CreateFirstFeature());
Bind<IFeature>().ToFeature<SecondFeature>().NamedLikeFactoryMethod((ISecondFeatureFactory o) => o.CreateSecondFeature());
Bind<IFirstFeatureFactory>().ToFactory();
Bind<ISecondFeatureFactory>().ToFactory();
Bind<IFeatureProvider>().To<FeatureProivder>();
这个'NameLikeFactoryMethod'绑定等同于我使用命名绑定here,它现在是the recommended way by ninject for factories。
这里要注意的重要事项是你没有自己实现IFirstFeatureFactory和ISecondFeatureFactory,而你正在使用ninject functionallity。
这个选项的主要缺点是当我们需要添加我们需要创建的更多功能时,除了功能本身另一个FeatureFactory之外,还要更改FeatureProvider来处理它。
如果功能没有经常更改,这个选项可以很好而且简单,但如果他们这样做可能会成为维护噩梦,这就是我建议选项2的原因。
选项二
在这个选项中,我们根本不会创建任何提供者类,并将所有创建逻辑放在工厂中
IFeatureFactory接口看起来与你现在的接口非常相似,但是我们不会使用int作为参数,而是使用一个字符串(我们很快就会看到更好的命名绑定)。
public interface IFeatureFactory
{
IFeature CreateFeature(string featureName);
}
我们不会自己实现这个接口,让ninject为我们做,但是我们需要告诉ninject使用CearteFeature的第一个参数来检测要实例化的实现(FirstFeatue或SecondFeature)。
为此,我们需要具有此行为的自定义实例提供程序作为StandardInstanceProvider,使用其他约定来选择要实例化的实现(默认约定in this article)。
幸运的是,ninject显示了我们如何通过UseFirstArgumentAsNameInstanceProvider快速实现它
现在绑定:
Bind<IFeature>().To<FirstFeature>().Named("FirstFeature");
Bind<IFeature>().To<FirstFeature>().Named("SecondFeature");
Bind<IFeatureFactory>().ToFactory(() => new UseFirstArgumentAsNameInstanceProvider());
这里要注意的事情:
这已解决了第一个选项中的问题,好像我们想要添加新功能,我们只需要创建它并将其绑定到他的名称接口。
现在工厂的客户可以从工厂特征中询问这个新名称,而无需在其他类中进行更改。
<强> Conslucsion 强>
通过选择上述选项中的一个而不是纯粹的di,我们将获得让ninject内核在工厂中创建我们的对象而不是自己完成所有“新”的好处。
虽然没有使用IoC容器没有任何问题,但这可以真正帮助我们在IFeature实现中有一个很大的依赖图,因为ninject会为我们注入它们。
通过执行其中一个选项,我们可以完全使用ninject功能,而无需使用被视为反模式的“服务定位器”。
答案 1 :(得分:1)
您可以将这些功能注入BasicFeatureFactory
的构造函数。
class BasicFeatureFactory : IFeatureFactory
{
FirstFeature feature1;
SecondFeature feature2;
public BasicFeatureFactory(FirstFeature feature1, SecondFeature feature2) {
this.feature1 = feature1;
this.feature2 = feature2;
}
public IFeature createFeature(int input) {
switch (input) {
case 1: return this.feature1;
case 2: return this.feature2;
default: return null;
}
}
}