我应该注入哪些依赖项?

Ale*_*lex 6 dependency-injection

使用依赖注入时,您注入哪些依赖项?

我以前注入了所有依赖项,但是在执行TDD时发现通常有两种类型的依赖项:

  • 那些是真正的外部依赖,可能会改变,例如ProductRepository
  • 纯粹为了可测试性而存在的那些例如,为了可测试性而提取和注入的类的行为的一部分

一种方法是注入这样的所有依赖项

public ClassWithExternalDependency(IExternalDependency external,
    IExtractedForTestabilityDependency internal)
{
    // assign dependencies ...
}
Run Code Online (Sandbox Code Playgroud)

但我发现这可能会导致DI注册表中的依赖性膨胀.

另一种方法是隐藏像这样的"可测试性依赖"

public ClassWithExternalDependency(IExternalDependency external)
    : this (external, new ConcreteClassOfInternalDependency())
{}

internal ClassWithExternalDependency(IExternalDependency external,
    IExtractedForTestabilityDependency internal)
{
    // assign dependencies ...
}
Run Code Online (Sandbox Code Playgroud)

这是更多的努力,但似乎更有意义.缺点不是所有对象都在DI框架中配置,从而打破了我听过的"最佳实践".

你会提倡哪种方法?为什么?

And*_*y S 1

我相信你最好注入所有依赖项。如果它开始变得有点笨拙,这可能表明您需要稍微简化一些事情或将依赖项移到另一个对象中。边走边感受设计的“痛苦”确实很有启发。

至于注册表中的依赖项膨胀,您可能会考虑使用某种传统的绑定技术,而不是手动注册每个依赖项。一些 IoC 容器内置了基于约定的类型扫描绑定。例如,以下是我在使用 Ninject 的 Caliburn WPF 应用程序中使用的模块的一部分:

public class AppModule : NinjectModule
{
    public override void Load()
    {
        Bind<IShellPresenter>().To<ShellPresenter>().InSingletonScope();

        BindAllResults();
        BindAllPresenters();
    }

    /// <summary>
    /// Automatically bind all presenters that haven't already been manually bound
    /// </summary>
    public void BindAllPresenters()
    {
        Type[] types = Assembly.GetExecutingAssembly().GetTypes();

        IEnumerable<Type> presenterImplementors =
            from t in types
            where !t.IsInterface
            && t.Name.EndsWith("Presenter")
            select t;

            presenterImplementors.Run(
                implementationType =>
                    {
                        if (!Kernel.GetBindings(implementationType).Any())
                            Bind(implementationType).ToSelf();
                    });
    }
Run Code Online (Sandbox Code Playgroud)

尽管我有数十个结果和演示者,但我不必明确注册它们。