防止实现细节泄漏到依赖注入容器的设置中

时间:2011-11-23 01:39:28

标签: dependency-injection separation-of-concerns

有时我们可以使用我们的DI容器做一些巧妙的技巧,例如:自动绑定,管理单例,管理每个请求的一个实例等。这很棒,并且可以真正简化某些场景。

我遇到的问题是,特定类的问题现在会泄漏到应用程序层。如果一个类期望以特定方式实例化和管理(例如,作为单个,或者每个http请求只执行一次),现在应该由应用程序层来确保这种情况发生。

发生的一些问题:

1)潜在的错误,因为应用程序可能错误地设置DI绑定。

2)当开发人员想要实现一个包时可能会造成混淆,因为设备DI容器的规则不是由包本身提供的,因此必须在注释或附带的测试用例中记录(不理想)。

3)如果类的实现发生了变化,现在每个应用程序都有责任使用该类来更新其DI容器绑定。

以下是一些使用NInject可以执行此操作的示例绑定:

public class MyApplicationsInjectionModule : NInjectModule
{
    public void Load()
    {
        Bind<IFoo>().ToConstant(FooThatShouldBeASingleton.Instant);

        Bind<IFoo>().To<FooThatShouldBeASingleton>().AsSingleton();

        Bind<IFoo>().To<FooThatShouldOnlyBeInstantiatedOncePerRequest>().InRequestScope();
    }
}

我的经验仅适用于NInject - 或许其他一些DI容器更优雅地处理这个问题。

在不放弃DI容器提供的功能的情况下,我们可以采取哪些策略来避免这些问题?

1 个答案:

答案 0 :(得分:2)

依赖注入引入了灵活性,并且具有这种灵活性还会增加错误编写对象图的风险。这是DI的一个(非常)缺点之一,它与您是否使用DI容器无关。

  

1)潜在的错误,因为应用程序可能错误地设置DI绑定。

with Poor Man's DI it's perfectly possible to compose an incorrect object graph

  

2)当开发人员想要实现一个包时可能会造成混淆,因为设备DI容器的规则不是由包本身提供的,因此必须在注释或附带的测试用例中记录(不理想)。

这就是为什么最好的策略(在.NET上)采用基于约定的配置。基本上,您可以告诉容器扫描所有适当的程序集,并根据它们实现的接口注册所有公共类。

如果您坚持构造函数注入自动连接将为您完成剩下的工作。

举个例子,假设您在程序集中定义了这个类:

public class Foo : IFoo
{
    private readonly IBar bar;

    public Foo(IBar bar)
    {
        if (bar == null)
            throw new ArgumentNullException("bar");

        this.bar = bar;
    }

    // Use this.bar for something interesting in the class...
}

在另一个集会中,你可能有

public class Bar : IBar { }

配置为扫描适当程序集的容器将找到Bar并将其注册为IBar,并且会找到Foo并将其注册到IFoo。由于Bar构造函数会静态地宣传其所需的依赖项,因此自动连接可以启动,容器将能够自动解析 IFoo

使用适当的约定,您无需重新配置容器即可向代码库添加新类型。

  

3)如果类的实现发生了变化,现在每个应用程序都有责任使用该类来更新其DI容器绑定。

同样,如果您使用约定优于配置,则会自动执行此操作。