.net 如何在不使用服务定位器模式的情况下使用依赖注入的工厂
我有一个GUI应用程序。在其中,我允许用户从容器提供的算法列表中进行选择。每个算法将作为另一个视图中的后台任务启动。我需要支持此视图的多个实例,并支持同一算法的多个实例。该视图也将由容器提供。该算法也是有状态的 因此,我需要创建视图和算法的实例,并在运行时将它们绑定在一起。我没有这些实例的静态绑定点,所以我不能使用普通的注入工具(构造函数或属性注入)。我不想调用.net 如何在不使用服务定位器模式的情况下使用依赖注入的工厂,.net,dependency-injection,ninject,factory-pattern,.net,Dependency Injection,Ninject,Factory Pattern,我有一个GUI应用程序。在其中,我允许用户从容器提供的算法列表中进行选择。每个算法将作为另一个视图中的后台任务启动。我需要支持此视图的多个实例,并支持同一算法的多个实例。该视图也将由容器提供。该算法也是有状态的 因此,我需要创建视图和算法的实例,并在运行时将它们绑定在一起。我没有这些实例的静态绑定点,所以我不能使用普通的注入工具(构造函数或属性注入)。我不想调用new,也不想像使用一个容器一样使用容器 我在Castle.Windsor解决了这个问题,但我不得不处理我应用程序中所有的工厂。工厂设计
new
,也不想像使用一个容器一样使用容器
我在Castle.Windsor解决了这个问题,但我不得不处理我应用程序中所有的工厂。工厂设计也有点奇怪,因为我必须在处理完实例后将它们返回工厂
我现在正在考虑使用NInject,因为到目前为止,学习曲线和简介文档要好得多,我想为我的团队推荐一个容器。但是对于这样的场景,我认为我必须编写自己的工厂并直接调用内核来解析新实例(工厂中嵌入的服务定位器),以及在注册代码中添加工厂方法
有没有一种通用的方法来解决这个问题,或者这仅仅是一个依赖注入本身并没有被设计来解决的问题
澄清: 我在评论中说,我想为Ninject提供一个具体的答案,我已经得到了。非常感谢:)在现实生活中,我可能会使用已经提出的务实解决方案 但我把我的问题搞砸了,把我的基础作为一个具体的问题。我希望我的标题中的问题能有一个更纯粹的基本答案 是否有一种纯DI技术允许用户在运行时触发组件的新实例?或者所有这些实现都将容器用作服务定位器,或者要求容器具有特定的“怪癖”(例如内置工厂支持、ala Castle.Windsor或即将发布的Ninject工厂功能),而不是只利用“纯”DI的各个方面
我只从Java世界听说过这个词,我不太明白它的意思——请原谅:)这就是我想要的某种“排斥”?最好创建这样的工厂界面
public interface IFooFactory
{
IFoo CreateFoo(int someParameter);
}
对于Ninject 2.3,请参阅,并让Ninject通过添加以下配置来实现它
Bind<IFooFactory>().AsFactory();
Bind().AsFactory();
对于2.2,您自己执行。此实现是容器配置的一部分,而不是实现的一部分
public class FooFactory: IFooFactory
{
private IKernel kernel;
public FooFactory(IKernel kernel)
{
this.kernel = kernel;
}
public ISession CreateFoo(int someParameter)
{
return this.kernel.Get<IFoo>(
new ConstructorArgument("someParameter", someParameter));
}
}
公共类FooFactory:IFooFactory
{
私有IKernel内核;
公共食品工厂(IKernel内核)
{
this.kernel=内核;
}
公共ISession CreateFoo(int-someParameter)
{
返回this.kernel.Get(
新构造函数参数(“someParameter”,someParameter));
}
}
我总是喜欢给出一般性的答案,而不太关注特殊容器的特性。你说的是:
IDisposable
对象来解决。然后可以编写如下代码:
using (var algorithm = this.algoFactory.CreateNew(type))
{
// use algorithm.
}
有多种方法可以做到这一点,但您可以让算法接口实现IDisposable
:
public interface IAlgorithm : IDisposable
{
}
您可以返回一个decorator,而不是返回实际算法,该decorator允许将该实例返回到池中:
public sealed class PooledAlgorithmDecorator : IAlgorithm
{
private readonly IAlgorithmPool pool;
private IAlgorithm real;
public PooledAlgorithmDecorator(IAlgorithm real,
IAlgorithmPool pool)
{
this.real = real;
this.pool = pool;
}
public void Dispose()
{
if (this.real != null)
{
this.Pool.ReturnToPool(this.real);
this.real = null;
}
}
}
现在,您的工厂可以使用decorator包装真正的算法,并将其返回给消费者:
public class PooledAlgorithmFactory : IAlgorithmFactory
{
private readonly IAlgorithmPool pool;
public PooledAlgorithmFactory(IAlgorithmPool pool)
{
this.pool = pool;
}
public IAlgorithm CreateNew(string type)
{
var instance = this.pool.GetInstanceOrCreateNew(type);
return new PooledAlgorithmDecorator(instance, this.pool);
}
}
这当然只是一个例子。您的设计可能会有所不同。根据您选择的容器,您可能会获得对工厂、对象池等的支持。我认为首先找到正确的设计是很重要的,下一步是看看您的容器是否能够帮助您解决这个问题。我非常感谢其他人的回答。他们会帮我解决这个问题。我很可能会接受雷莫的答案,因为它符合我目前实际面临的问题 就我的理解而言,我还想就我提出的这个更广泛的答案获得反馈
我不确定依赖项注入是否通过构造函数、属性或方法注入直接支持我提到的机制。这就是我现在认为的“纯”DI——虽然我愿意被动摇。< /P> 我认为注入依赖性意味着相对静态的对象图。它可以从配置文件加载,也可以按程序生成,但它不能直接适应未知的运行时状态,就像用户反复请求新实例一样 然而,在考虑了其中的一些替代方案后,我开始认为有一些解决方案支持纯度,也许我描述的纯度没有我想象的那么重要。一些不太“纯粹”的选项仍然以一种非常干净的方式在大多数容器中工作,并且似乎很容易添加对容器的支持,以便在剩下的过程中清理它们 以下是我到目前为止考虑的解决方案(其中一些已经提到) 参考定制工厂的容器,然后洗手: 您的组件可以根据需要实现。您可以使用任何您想要的容器(只要它支持瞬态实例)。您只需要接受这样一个事实,即您将向代码中注入工厂,这些工厂将直接从容器中解析。当你可以成为布拉格时,谁需要纯洁
public class ComponentFactory // Might inherit from an interface...
{
private readonly IContainer container;
public ComponentFactory(IContainer container)
{
this.container = container;
}
public IComponent Create(IOtherComponent otherComponent)
{
return container.Get<IComponent>(otherComponent);
}
}
// Black magic - the container implemented it for us!
// But the container basically implemented our code from the previous example...
public interface IComponentFactory
{
public IComponent Create(IOtherComponent otherComponent);
}
public class SomeUI
{
private readonly IComponentPool componentPool;
public OtherComponent(IComponentPool componentPool)
{
this.componentPool = componentPool;
}
public void DoSomethingWhenButtonPushed()
{
var component = componentPool.Get();
component.DoSomething();
componentPool.Release(component);
}
}
public class ComponentState
{
// Hopefully can be less generic than this...
public Dictionary<string, object> Data { get; set; }
}
public interface IComponent
{
int DoSomething(ComponentState state);
}
public SomeUI
{
private readonly IComponent component;
public OtherComponent(IComponent component)
{
this.component = component;
}
public void DoSomethingWhenButtonPushed()
{
var state = new ComponentState();
component.DoSomething(state);
}
}
public class SubComponentFactory // Might inherit from an interface...
{
private readonly IContainer container;
public ComponentFactory(IContainer container)
{
this.container = container;
}
public IComponent Create(IOtherComponent otherComponent)
{
// Todo: Figure out any lifecycle issues with this.
// I assume the child containers get disposed with the parent container...
var childContainer = container.CreateChildContainer();
childContainer.Configure(new SubComponentConfiguration());
return childContainer.Get<SubComponent>(otherComponent);
}
}