我最近一直在想,从设计的角度看Log()和Log(LogLevel)之间有什么真正的区别吗?
例如,在log4net中,ILog接口的设计如下。
// Design A
public interface ILog
{
/* Log a message object */
void Debug(object message);
void Info(object message);
void Warn(object message);
void Error(object message);
void Fatal(object message);
// ... ignore more members
}
但我认为它等同于这样设计。
// Design B
public enum LogLevel
{
Debug,
Info,
Warn,
Error,
Fatal
}
public interface ILog
{
/* Log a message object */
void Log(LogLevel level, object message);
// ... ignore more members
}
那为什么log4net不使用设计B?有什么特别的原因吗?
我能想到的一个原因是,设计A减少了调用者的代码噪声,每次都指定类似LogLevel.Info的内容。
但是设计B也可以有一个好处,我们可以在一次通话中改变消息的严重性。例如logger.Log(some_bool_condition?LogLevel.Warning:LogLevel.Error)。但是,当然,我们可以创建一个包装来执行与设计A类似的操作。
答案 0 :(得分:1)
从技术上讲,这两种方法都可以从ILog
访问,因为它来自ILoggerWrapper
。从那里你可以获得一个ILogger,它允许你直接调用方法作为你正在描述的方法B:
void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception);
void Log(LoggingEvent logEvent);
所以让ILog
主要减少代码噪音,并且只是在幕后调用记录器:
// log4net.Core.LogImpl
public virtual void Info(object message)
{
this.Logger.Log(LogImpl.ThisDeclaringType, this.m_levelInfo, message, null);
}
显然这里有一些不同解释的空间,但这就是为什么我认为最好使用Debug / Info / Warn / Error / Fatal方法而不是通用Log(级别)方法。通过强制您的代码使用一种方法,库强制它在撰写时断言信息在您应用范围内的重要性。
如果您可以将级别推迟到某个更高的层次结构,您只需说"哦,让呼叫者决定他们希望从我的组件中听到多少"。但是他们无法知道某些东西对你的组件是否重要。您的代码会塑造所需的信息;应用程序用户不想听到它让他通过配置让你的记录器保持沉默,但只有你的代码知道缺少的SQL服务器是否会引起警报或只是一些轻微的麻烦(来自最近的开发人员,其中一个数据库只要过去曾经回答过一次,我的组件服务器就会消失而没有问题。