为什么要使用singleton进行应用程序日志

Nem*_*emo 5 c# singleton

我正在阅读单身模式的缺点.在许多论坛中建议的有效使用单例是Logging应用程序.我想知道为什么这是模式的有效使用.我们不是在整个应用程序中维护内存中的状态信息吗?

为什么不使用一个函数:

class Logger
{
    public static void Log(string message)
    {
         //Append to file

    }
}
Run Code Online (Sandbox Code Playgroud)

Che*_*hen 5

要回答“为什么不只使用函数”:此代码在多线程日志记录中工作不正确。如果两个线程尝试写入同一个文件,则会抛出异常。这就是为什么最好使用单例进行日志记录的原因。在这个解决方案中,我们有一个线程安全的单例容器,其他线程安全地将消息(日志)推送到容器中。并且容器(始终是线程安全队列)将消息/日志一一写入文件/db/etc。


Luk*_*Led 2

最好声明接口:

interface ILogger
{
    public void Log(string message);
}
Run Code Online (Sandbox Code Playgroud)

然后实现特定类型的logger

class FileLogger : ILogger
{
    public void Log(string message)
    {
         //Append to file
    }
}

class EmptyLogger : ILogger
{
    public void Log(string message)
    {
         //Do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

并在需要的地方注射。您将注入EmptyLogger测试。使用单例将使测试变得更加困难,因为您也必须在测试中保存到文件。如果您想测试类是否生成正确的日志条目,您可以使用模拟并定义期望。

关于注射:

public class ClassThatUsesLogger
{
    private ILogger Logger { get; set; }
    public ClassThatUsesLogger(ILogger logger) { Logger = logger }
}
Run Code Online (Sandbox Code Playgroud)

ClassThatUsesLogger 在生产代码中采用 FileLogger:

classThatUsesLogger = new ClassThatUsesLogger(new FileLogger());
Run Code Online (Sandbox Code Playgroud)

在测试中它需要 EmptyLogger:

classThatUsesLogger = new ClassThatUsesLogger(new EmptyLogger());
Run Code Online (Sandbox Code Playgroud)

您可以在不同的场景中注入不同的记录器。有更好的方法来处理注入,但您必须阅读一些内容。

编辑

请记住,您仍然可以在代码中使用单例,正如其他人所建议的那样,但是您应该将其用法隐藏在接口后面,以放松类与日志记录的特定实现之间的依赖关系。