我有一个根项目(root
),一些模块(A
,B
),并且这些模块具有一些外部依赖项(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
服务上进行配置吗?
在这种情况下(有点极端),内部使用类的配置又如何呢?
答案 0 :(得分:1)
假设这些扩展方法是在应用程序的Composition Root中定义的,为什么不从AddDependencyZ
和AddModuleA
中删除对AddModuleB
的调用?>
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.
//...
}
然后,您将在编写时在“合成根目录”中配置容器(这是RRR pattern中的 Register 阶段):
services.AddModuleA();
services.AddModuleB();
services.AddDependencyZ();
这是否违反了最低知识原则?是的,的确如此,但这是使用DI容器的众多缺点之一。
我建议使用Pure DI,而不要使用DI容器。这将使问题消失,因为OP中的所有代码都是多余的。