使用哪种模式进行日志记录?依赖注入或服务定位器?

Cod*_*nia 34 c# design-patterns dependency-injection service-locator

考虑这种情况.我有一些业务逻辑,现在需要写入日志.

interface ILogger
{
    void Log(string stuff);
}

interface IDependency
{
    string GetInfo();
}

class MyBusinessObject
{
    private IDependency _dependency;

    public MyBusinessObject(IDependency dependency)
    {
        _dependency = dependency;
    }

    public string DoSomething(string input)
    {
        // Process input
        var info = _dependency.GetInfo();
        var intermediateResult = PerformInterestingStuff(input, info);

        if (intermediateResult== "SomethingWeNeedToLog")
        {
            // How do I get to the ILogger-interface?
        }

        var result = PerformSomethingElse(intermediateResult);

        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

你会如何获得ILogger界面?我看到两种主要的可能性;

  1. 在构造函数上使用依赖注入传递它.
  2. 通过单一服务定位器获取它.

你更喜欢哪种方法,为什么?还是有更好的模式?

更新: 请注意,我不需要记录所有方法调用.我只想记录在我的方法中可能发生或可能不发生的一些(罕见)事件.

And*_*mes 15

我个人将两者混合在一起.

这是我的约定:

  • 从静态上下文 - 服务位置
  • 从实例上下文 - 依赖注入

我觉得这给了我可测试性的正确平衡.我发现对使用服务位置而不是使用DI的类设置测试有点困难,所以这就是服务位置最终成为例外而不是规则的原因.不过,我的使用是一致的,所以要记住我需要编写什么类型的测试并不难.

一些人提出了DI倾向于使构造者混乱的担忧.我不认为这是一个问题,但如果你有这种感觉,有许多替代方案使用DI,但避免构造函数参数.以下是Ninject的DI方法列表:http://ninject.codeplex.com/wikipage?title = Injection% 20Patterns

您会发现大多数Inversion of Control容器具有与Ninject相同的功能.我选择展示Ninject因为他们有最简洁的样本.

希望这很有帮助.

编辑:要清楚,我使用Unity和Common Service Locator.我有一个用于DI的Unity容器的单例实例,我的IServiceLocator实现只是该单例Unity容器的包装器.这样我就不必做任何类型映射两次或类似的事情.

除了追踪之外,我也没有发现AOP特别有用.我更喜欢手动记录,只是为了清晰.我知道大多数AOP日志框架都能够兼顾,但我大多数时候都不需要前者(AOP的面包和黄油).当然,这只是个人偏好.


Pet*_*old 7

记录器显然是您的业务逻辑所依赖的服务,因此应该以与您相同的方式将其视为依赖项IDependency.在构造函数中注入记录器.

注意:即使提到AOP作为注入日志记录方式,我也不同意它是这种情况下的解决方案.AOP非常适合执行跟踪,但永远不会成为日志作为业务逻辑的一部分的解决方案.

  • *记录器显然是您的业务逻辑所依赖的服务*-我不同意这一点。您的业​​务逻辑绝不应该依赖于日志记录,而没有它,您的应用程序也应该可以正常运行。您的调试会话,但是... (2认同)

Aar*_*ght 5

我的小经验法则:

  • 如果它在类库中,请使用构造函数注入或使用null对象模式的属性注入.

  • 如果它在主应用程序中,请使用服务定位器(或单例).

我发现这在使用log4net时非常适用.您不希望类库与可能不存在的东西联系,但在应用程序中,您知道记录器将会存在,并且像log4net这样的库很大程度上依赖于服务位置模式.

我倾向于认为日志记录是足够静态的,它并不真正需要DI.我不太可能在应用程序中更改日志记录实现,特别是因为每个日志记录框架都非常灵活且易于扩展.在类库中,当您的库可能需要由已使用不同记录器的多个应用程序使用时,这一点更为重要.

YMMV,当然.DI很棒,但这并不意味着一切都需要DI.


Fka*_*Fka 5

也许这会有点离题,但是为什么我们需要注入记录器,因为我们可以在类的开头输入:

Logger logger = LogManager.GetLogger("MyClassName");
Run Code Online (Sandbox Code Playgroud)

Logger 在开发期间和后期维护期间不会更改。现代记录器是高度可定制的,所以论点

如果我想用数据库替换文本记录器怎么办?

错过了。

我不否定使用依赖注入,我只是对你的想法感到好奇。

  • 完全同意。例如,log4net 可以配置为基本上记录任何内容,您也可以编写自己的适配器。通过这种方式,您知道使用了哪个记录器,在注入时很难弄清楚 (3认同)