我最近问过正确地做DI,并获得了一些关于它的博客文章的链接。我想我现在有了更好的理解 - 通过将它放在工厂中,将逻辑分离出来。但是所有的例子都是针对像网站这样的东西,并且说要在启动时做所有的接线。调用一个大工厂new
所有的东西,并传递所有依赖项。
但如果我不想事先实例化一切呢?我有一个对象,其中包含可以委派给的其他对象的列表,但它们很昂贵,并且一次只使用一个,所以我在需要时构建它们,并在完成后让它们被收集。我不想将new B()
放在A
的逻辑中,因为我宁愿使用DI - 但是如何?可A
致电工厂吗?除非工厂维持包括当前依赖关系的状态,否则这似乎并没有好多少。我只是不想在B
构建时将A
的完整列表传递给B
,因为这会浪费。如果您愿意,A
不一定 位于A
内,尽管它具有逻辑意义(B
是游戏级别,{{1} }是单个屏幕),但无论如何A
的逻辑决定了何时创建B
。
那么,谁叫工厂获得B
,何时?
澄清:我没有使用DI的框架。我想知道DI这个词是否意味着什么?
答案 0 :(得分:6)
在Ninject中,您可以注册Func<B>
并在构造函数中请求A
。
如果Func<B>
已经注册,Autofac将自动提供B
。
或者,您可以采用更直接的方法并为B
定义显式工厂,并在构造函数中请求该工厂;它只是更多的打字,因为你必须为你想懒洋洋地初始化的每个依赖创建一个工厂。
这是另一个显示Ninject样式工厂方法的答案:How do I handle classes with static methods with Ninject?
@Not使用框架:如果可以的话,我可能会考虑使用一个:IoC / DI框架通常会为您提供开箱即用的延迟创建。
如果您想继续自己动手,那么只需将创建B的工厂传递给您的A对象。或者,如果您不喜欢原始Func并且不想为所有对象创建显式工厂,那么您可以考虑使用Lazy<B>
来获得更正式的解决方案。
答案 1 :(得分:1)
通常有两种模式可以使用很少需要创建的对象。 David Faivre建议,第一种模式是使用工厂。另一种是使用代理。
代理是从设计的角度来看 - 可能是最干净的解决方案,尽管它可能需要更多代码来实现。它是最干净的,因为应用程序可能完全没有意识到这一点,因为您不需要额外的接口(因为工厂方法需要)。
这是一个带有一些接口和昂贵实现的简单示例:
interface IAmAService
{
void DoSomething();
}
class ExpensiveImpl : IAmAService
{
private object x = [some expensive init];
void IAmAService.DoSomething() { }
}
不,您可以基于该接口实现代理,这可能会延迟该实现的创建:
class ServiceProxy : IAmAService
{
private readonly Func<IAmAService> factory;
private IAmAService instance;
public ServiceProxy(Func<IAmAService> factory)
{
this.factory = factory;
}
void IAmAService.DoSomething()
{
this.GetInstance().DoSomething();
}
private IAmAService GetInstance()
{
// TODO: Implement double-checked lock only a single
// instance may exist per ServiceProxy.
if (this.instance == null)
{
this.instance = this.factory();
}
return this.instance;
}
}
此代理类接受工厂委托作为依赖关系,就像David Faivre在他的回答中所描述的那样,但这样应用程序不必依赖于Func<IAmAService>
,而只能依赖于IAmAService
}。
现在,您可以将ExpensiveImpl
注入其他实例,而不是注入ServiceProxy
:
// Create the proxy
IAmAService service =
new ServiceProxy(() => new ExpensiveImpl());
// Inject it into whatever you wish, such as:
var customerService = new CustomerService(service);