创建具有依赖项的对象 - 依赖注入

时间:2011-11-17 18:43:38

标签: dependency-injection inversion-of-control ioc-container

假设我们上课了:

public class WithDependencies
{
  public WithDependencies(IAmDependencyOne first, IAmDependencyTwo second)
  // ...
}

现在的问题。如何在应用程序中创建WithDependencies类的对象? 我知道有很多方法。

new WithDependencies(new DependencyOne(), new DependencyTwo());
new WithDependencies(IoC.Resolve(IDependencyOne), IoC.Resolve(IDependencyTwo());
// register IDependencyOne, IDependencyTwo implementations at app start
IoC.Resolve(WithDependencies);
// register IDependencyOne, IDependencyTwo implementations at app start
// isolate ourselves from concrete IoC Container
MyCustomWithDependenciesFactory.Create();

依旧......

您认为如何做到这一点?

编辑:

因为我没有得到答案或我不理解他们,我会再试一次。让我们说在某些事件(按钮,计时器,等等)上我需要新的对象WithDependencies()。我该如何创建它?假设已经配置了IoC容器。

3 个答案:

答案 0 :(得分:3)

这取决于具体情况,因此无法提供单一答案。 从概念上你将从Composition Root

做这样的事情
var wd = new WithDependencies(new DependencyOne(), new DependencyTwo());

然而,即使没有DI容器,上面的代码并不总是毫无疑问是正确的答案。在某些情况下,您可能希望在多个使用者之间共享相同的依赖关系,如下所示:

var dep1 = new DependencyOne();
var wd = new WithDependencies(dep1, new DependencyTwo());
var another = AnotherWithDependencies(dep1, new DependencyThree());

在其他情况下,您可能想要共享依赖项,在这种情况下,第一个选项更正确。

这只是与终身管理相关的DI的整个维度的一小部分。许多DI容器可以为您解决这个问题,这是偏爱DI容器而不是穷人DI的一个很好的理由。

一旦开始使用DI容器,在解析类型时应遵循Register Resolve Release pattern,让自动连接处理实际构图:

var wd = container.Resolve<WithDependencies>();

上面的示例假定容器已正确配置。

答案 1 :(得分:2)

如果您需要创建一个具有自己的依赖关系的依赖项,您可以A)自己动手,或者B)请求其他人为您执行此操作。选项A否定了依赖注入(解耦等)的好处,所以我认为选项B是一个更好的起点。现在,我们选择使用工厂模式,无论它是采用服务定位器(即IoC.Resolve),静态工厂还是实例工厂的形式。关键是我们已将这一责任委托给外部机构。

静态访问器需要进行多种权衡。 (I went over them in another answer,所以我不会在这里重复它们。)为了避免在基础设施或容器上引入依赖,一个可靠的选择是在我们需要时接受工厂来创建WithDependencies实例在其他地方:

public class NeedsWithDependencies
{
    private readonly IWithDependenciesFactory _withDependenciesFactory;

    public NeedsWithDependencies(IWithDependenciesFactory withDependenciesFactory)
    {
        _withDependenciesFactory = withDependenciesFactory;
    }

    public void Foo()
    {
        var withDependencies = _withDependenciesFactory.Create();

        ...Use the instance...
    }
}

接下来,我们可以创建一个特定于容器的工厂实现:

public class WithDependenciesFactory : IWithDependenciesFactory
{
    private readonly IContainer _container;

    public WithDependenciesFactory(IContainer container)
    {
        _container = container
    }

    public WithDependencies Create()
    {
        return _container.Resolve<WithDependencies>();
    }
}

现在NeedsWithDependenciesWithDependencies如何创建完全隔离;它还在其构造函数中公开其所有依赖项,而不是隐藏对静态访问器的依赖,使其易于重用和测试。

但是,定义所有这些工厂可能会变得有点麻烦。我喜欢Autofac's factory relationship type,它将检测Func<TDependency>形式的参数并自动注入一个与上述手工编码工厂具有相同目的的函数:

public class NeedsWithDependencies
{
    private readonly Func<WithDependencies> _withDependenciesFactory;

    public NeedsWithDependencies(Func<WithDependencies> withDependenciesFactory)
    {
        _withDependenciesFactory = withDependenciesFactory;
    }

    public void Foo()
    {
        var withDependencies = _withDependenciesFactory();

        ...Use the instance...
    }
}

它也适用于运行时参数:

public class NeedsWithDependencies
{
    private readonly Func<int, WithDependencies> _withDependenciesFactory;

    public NeedsWithDependencies(Func<int, WithDependencies> withDependenciesFactory)
    {
        _withDependenciesFactory = withDependenciesFactory;
    }

    public void Foo(int x)
    {
        var withDependencies = _withDependenciesFactory(x);

        ...Use the instance...
    }
}

答案 2 :(得分:0)

有时我试图摆脱工厂或者至少不直接依赖它们,所以依赖注入(没有工厂)当然是有用的。

因此,我使用Google Juice,使用Java Annotations创建一个小小框架,您可以快速更改注入/依赖项。看看吧:

http://code.google.com/p/google-guice/