【问题标题】:Handle IoC configuration with shared dependencies between projects使用项目之间的共享依赖关系处理 IoC 配置
【发布时间】:2019-05-23 17:50:59
【问题描述】:

我有一个根项目(root),一些模块(AB),这些模块有一些外部依赖项(Z)。我正在使用 IoC 容器。

我在这里使用 C#,但这是一个通用模式问题。假设我的容器是services,我可以使用扩展方法初始化 IoC 配置。所以在root 项目中我正在写:

services.AddModuleA();
services.AddModuleB();

在模块A我有这个方法:

public static void AddModuleA(this IServiceCollection services)
{
    // Init module internal services.
    //services.AddScoped<IA1Service, A1Service>();
    //...

    // Init module external dependencies.
    services.AddDependencyZ();
}

在模块B我有一个类似的方法:

public static void AddModuleB(this IServiceCollection services)
{
    // Init module internal services.
    //...

    // Init module external dependencies.
    services.AddDependencyZ();
}

显然Z 依赖已经被添加,所以这告诉我我不应该在模块扩展方法中配置它,我应该在root 项目中声明它的配置:

services.AddModuleA();
services.AddModuleB();
services.AddDependencyZ();

但这不违反最少知识原则吗?导入和配置模块A(或B)将带来所有依赖配置的级联显式声明。

还有相关的问题,声明扩展方法AddModuleA()AddModuleB() 是不是一个糟糕的模式?直接在root 上仅配置我将使用的服务可能是一个更好的主意吗? 而在这种情况下(有点极端),内部使用类的配置呢?

【问题讨论】:

  • 考虑使用TryAddDependencyZ(),在尝试添加之前先检查它是否尚未添加。

标签: design-patterns dependency-injection configuration inversion-of-control


【解决方案1】:

假设这些扩展方法是在您的应用程序的Composition Root 中定义的,为什么不直接从AddModuleAAddModuleB 中删除对AddDependencyZ 的调用?

public static void AddModuleA(this IServiceCollection services)
{
    // Init module internal services.
    //services.AddScoped<IA1Service, A1Service>();
    //...
}

public static void AddModuleB(this IServiceCollection services)
{
    // Init module internal services.
    //...
}

然后,您将在编写时在 Composition Root 中配置容器(这是 RRR pattern 中的 Register 阶段):

services.AddModuleA();
services.AddModuleB();
services.AddDependencyZ();

这是否违反了最少知识原则?是的,确实如此,但这是使用 DI 容器的众多缺点之一。

我推荐Pure DI 而不是使用 DI 容器。这将使问题消失,因为 OP 中的所有代码都是多余的。

【讨论】:

    猜你喜欢
    • 2012-03-24
    • 2018-01-15
    • 2016-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-23
    相关资源
    最近更新 更多