基础设施依赖项是否应该注入?

4

对于诸如日志记录器、安全性、配置等基础设施项目,它们是否真的应该注入到每个需要它们的类中,还是应该将它们注入到服务定位器中,然后类可以使用服务定位器来解决依赖关系(或其他机制)?

在我的看法中,所有的类都必须通过DI满足依赖关系,这看起来确实非常荒谬。我认为这是一种代码味道。我可以理解类似存储库或服务代理/连接器等内容,但不包括日志记录。


1
你可以将它们注入到全局应用程序上下文中,并从中消费。毕竟,容器是单例的单例。 - DarthVader
2
这种气味可能不是来自于你的 DI,而是来自于你的 10 参数类,可能违反了做一件事并做好它的哲学。 - ken
@ken 这就是我的观点,DI 不是一种代码坏味道,而是那个拥有 10 个参数的构造函数。 - ILovePaperTowels
3个回答

4
有几个选项。
  1. use property injection and set the default in the ctor. for example

    class foo 
    {
        public ILogger Logger {get;set;}
    
        public foo()
        {
           Logger = NullLogger.Instance;
        }
    }
    
  2. use an AOP type approach. using a dynamic proxy you can wrap public calls with logging statements but the logging is never actually injected into the component itself. See Castle.DynamicProxy or custom .Net Attribute for more ideas on this approach.

然后就有一个问题,为什么会有这么多基础设施的问题注入到组件中呢?你所描述的被认为是交叉关注点,通常可以通过某种AOP(面向切面编程)来处理,以便在核心系统中减少大量重复。


2
+1 for AOP。通常我会同意你关于AOP的看法,但我不喜欢运行时AOP框架,而且团队也不理解AOP概念。他们几乎不了解IoC概念。 - ILovePaperTowels
我完全理解 :) 你更好的选择是使用可选属性注入的 #1。我无法忍受服务定位器,它感觉就像纯IoC的垫片一样不正确。 - Jason Meckley

2
一切都取决于您在基础设施和其他代码之间划分界限的位置。您认为数据库连接是基础设施吗?我不这么认为。
属性注入是一种代码味道,因为它隐藏了依赖关系,并且当构造函数完成时未正确初始化类。只有在解决循环依赖关系时才使用它。
对于记录日志的非常特殊情况,我确实使用单例来获取记录器。

通常我会同意您关于AOP的看法,但我不喜欢运行时AOP框架,而且团队不理解AOP概念。他们几乎不了解IoC概念

您可能会发现我的IoC介绍有用。

1
关于日志记录 - 只需使用NLog(或您喜欢的记录器)即可完成。除非您处于一个非常奇怪的情况,否则没有理由抽象和/或注入您的记录器。
关于配置 - 只有少数类应该是配置的消费者,因此这不应该导致构造函数膨胀。另请参见this question以获取有关配置和DI的良好讨论。
关于安全性 - 再次,我认为只有少数类应该是安全性依赖项的消费者。如果许多类都涉及安全性,则可能需要重新审视设计。
总的来说 - 如果一个类有太多的构造函数参数,那么它可能做了太多的事情,无论依赖关系是否基础设施相关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接