是否有用于初始化通过 DI 容器创建的对象的模式 [英] Is there a pattern for initializing objects created via a DI container
问题描述
我正在尝试让 Unity 管理我的对象的创建,并且我想要一些直到运行时才知道的初始化参数:
I am trying to get Unity to manage the creation of my objects and I want to have some initialization parameters that are not known until run-time:
目前我能想到的唯一方法是在接口上有一个 Init 方法.
At the moment the only way I could think of the way to do it is to have an Init method on the interface.
interface IMyIntf {
void Initialize(string runTimeParam);
string RunTimeParam { get; }
}
然后(在 Unity 中)使用它,我会这样做:
Then to use it (in Unity) I would do this:
var IMyIntf = unityContainer.Resolve<IMyIntf>();
IMyIntf.Initialize("somevalue");
在这种情况下,runTimeParam
参数是在运行时根据用户输入确定的.这里的小例子只是返回 runTimeParam
的值,但实际上参数将类似于文件名,而 initialize 方法将对文件执行某些操作.
In this scenario runTimeParam
param is determined at run-time based on user input. The trivial case here simply returns the value of runTimeParam
but in reality the parameter will be something like file name and initialize method will do something with the file.
这会产生许多问题,即 Initialize
方法在接口上可用并且可以多次调用.在实现中设置一个标志并在重复调用 Initialize
时抛出异常似乎很笨拙.
This creates a number of issues, namely that the Initialize
method is available on the interface and can be called multiple times. Setting a flag in the implementation and throwing exception on repeated call to Initialize
seems way clunky.
在我解析我的接口时,我不想知道任何关于 IMyIntf
的实现.不过,我确实想要知道该接口需要某些一次性初始化参数.有没有办法以某种方式用这些信息注释(属性?)接口,并在创建对象时将它们传递给框架?
At the point where I resolve my interface I don't want to know anything about the implementation of IMyIntf
. What I do want, though, is the knowledge that this interface needs certain one time initialization parameters. Is there a way to somehow annotate(attributes?) the interface with this information and pass those to framework when the object is created?
对界面进行了更多描述.
Described the interface a bit more.
推荐答案
任何需要运行时值来构建特定依赖项的地方,抽象工厂就是解决方案.
Any place where you need a run-time value to construct a particular dependency, Abstract Factory is the solution.
在接口上使用 Initialize 方法有一种抽象抽象的味道.
Having Initialize methods on the interfaces smells of a Leaky Abstraction.
在您的情况下,我会说您应该根据如何使用它来建模 IMyIntf
接口 - 而不是您打算如何创建其实现.这是一个实现细节.
In your case I would say that you should model the IMyIntf
interface on how you need to use it - not how you intent to create implementations thereof. That's an implementation detail.
因此,界面应该是:
public interface IMyIntf
{
string RunTimeParam { get; }
}
现在定义抽象工厂:
public interface IMyIntfFactory
{
IMyIntf Create(string runTimeParam);
}
您现在可以创建 IMyIntfFactory
的具体实现,它创建 IMyIntf
的具体实例,如下所示:
You can now create a concrete implementation of IMyIntfFactory
that creates concrete instances of IMyIntf
like this one:
public class MyIntf : IMyIntf
{
private readonly string runTimeParam;
public MyIntf(string runTimeParam)
{
if(runTimeParam == null)
{
throw new ArgumentNullException("runTimeParam");
}
this.runTimeParam = runTimeParam;
}
public string RunTimeParam
{
get { return this.runTimeParam; }
}
}
请注意这如何允许我们通过使用 readonly
关键字保护类的不变量.不需要有臭味的 Initialize 方法.
Notice how this allows us to protect the class' invariants by use of the readonly
keyword. No smelly Initialize methods are necessary.
一个 IMyIntfFactory
实现可能像这样简单:
An IMyIntfFactory
implementation may be as simple as this:
public class MyIntfFactory : IMyIntfFactory
{
public IMyIntf Create(string runTimeParam)
{
return new MyIntf(runTimeParam);
}
}
在您需要 IMyIntf
实例的所有消费者中,您只需通过构造函数注入请求它来依赖于 IMyIntfFactory
.
In all your consumers where you need an IMyIntf
instance, you simply take a dependency on IMyIntfFactory
by requesting it through Constructor Injection.
如果您正确注册,任何有价值的 DI Container 都可以为您自动连接 IMyIntfFactory
实例.
Any DI Container worth its salt will be able to auto-wire an IMyIntfFactory
instance for you if you register it correctly.
这篇关于是否有用于初始化通过 DI 容器创建的对象的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!