对于记录器、安全性、配置等基础设施项目,这些东西应该真正注入到需要它们的每个类中,还是应该注入到服务定位器中,然后这些类可以使用服务定位器来解决依赖关系(或一些其他机制)?
所有类都有 10 个参数 ctor 来通过 DI 满足依赖关系,这看起来真的很荒谬。它是一种代码气味 IMO。我能理解诸如存储库或服务代理/连接器之类的东西,但不能理解日志。
对于记录器、安全性、配置等基础设施项目,这些东西应该真正注入到需要它们的每个类中,还是应该注入到服务定位器中,然后这些类可以使用服务定位器来解决依赖关系(或一些其他机制)?
所有类都有 10 个参数 ctor 来通过 DI 满足依赖关系,这看起来真的很荒谬。它是一种代码气味 IMO。我能理解诸如存储库或服务代理/连接器之类的东西,但不能理解日志。
有几个选择。
使用属性注入并在 ctor 中设置默认值。例如
class foo
{
public ILogger Logger {get;set;}
public foo()
{
Logger = NullLogger.Instance;
}
}
Castle.DynamicProxy
或自定义 .Net 属性。那么问题来了,为什么要向组件中注入如此多的基础设施问题?您所描述的被认为是横切关注点,通常这是通过一些 AOP(面向方面的编程)来处理的,因此核心系统中没有很多重复。
这完全取决于您在基础设施和其余代码之间划清界限的位置。你认为数据库连接是基础设施吗?我不。
属性注入是一种代码味道,因为它隐藏了依赖关系,并且在构造函数完成时没有正确初始化类。只用它来解决循环依赖。
对于非常具体的记录情况,我确实使用单例来获取记录器。
通常我会同意你对 AOP 的看法,但我不是运行时 AOP 框架的粉丝,而且团队不了解 AOP 概念。他们几乎不了解 IoC 概念
您可能会发现我的IoC 介绍很有用。
关于日志记录 - 只需使用 NLog(或您最喜欢的记录器)并完成它。除非您处于一个非常奇怪的场景中,否则没有理由抽象和/或注入您的记录器。
关于配置 - 只有少数类应该是配置的消费者,所以这不应该导致构造函数膨胀。有关配置和 DI 的详细讨论,另请参阅此问题。
关于安全性 - 同样,我认为只有少数类应该是安全依赖项的消费者。如果许多类都与安全有关,您可能需要重新审视您的设计。
一般来说 - 如果一个类有太多的构造函数参数,可能是因为它做的太多了,不管依赖项是否是基础设施。