是否有用于初始化通过 DI 容器创建的对象的模式 [英] Is there a pattern for initializing objects created via a DI container

本文介绍了是否有用于初始化通过 DI 容器创建的对象的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆