在软件开发中,日志记录是一个重要的功能,它可以帮助开发者监控程序的运行状态和调试程序。在多层架构中,业务层通常需要记录一些关键的操作,但如何将这些日志信息传递到表示层是一个常见的问题。本文将介绍一种使用复合模式来解决这个问题的方法。
假设有一个在业务层执行大量更新的函数,希望在这些更新过程中记录下确切的操作。希望能够轻松地将活动描述的字符串记录到以下一个或多个日志记录器中:文本框、列表框、文本文件和/或系统事件日志。
为了保持示例的简单性,将实现一个简单的ILogger接口,该接口只要求日志类实现自己的日志记录方式。
public interface ILogger
{
void LogMessage(string strMessage);
}
将创建以下日志记录类:
注意,列表框和文本框日志记录器是线程安全的,通过使用InvokeRequired方法。
class ListBoxLogger : ILogger
{
ListBox m_listBox;
public ListBoxLogger(ListBox listBox)
{
m_listBox = listBox;
}
public void LogMessage(string strMessage)
{
MethodInvoker logDelegate = delegate
{
m_listBox.Items.Add(strMessage);
};
if (m_listBox.InvokeRequired)
m_listBox.Invoke(logDelegate);
else
logDelegate();
}
}
class TextBoxLogger : ILogger
{
private TextBox m_textBox;
public TextBoxLogger(TextBox txtBox)
{
m_textBox = txtBox;
}
public void LogMessage(string strLogMessage)
{
MethodInvoker logDelegate = delegate { m_textBox.Text = strLogMessage; };
if (m_textBox.InvokeRequired)
m_textBox.Invoke(logDelegate);
else
logDelegate();
}
}
文件日志记录器是线程安全的,并且在写入前打开和关闭文件,这保证了每次调用LogMessage后消息都被刷新。
class FileLogger : ILogger
{
private string m_strFileName;
private object m_sync = new object();
public FileLogger(string strFileName)
{
m_strFileName = strFileName;
}
public void LogMessage(string strMessage)
{
lock (m_sync)
{
using (StreamWriter writer = new StreamWriter(m_strFileName))
{
writer.WriteLine(strMessage);
}
}
}
}
class EventLogger : ILogger
{
public EventLogger()
{
}
public void LogMessage(string strMessage)
{
EventLog.WriteEntry("Logger", strMessage);
}
}
到目前为止,没有什么特别的;可以有一个函数,它接受一个ILogger对象,并允许记录消息。例如:
private void DoSomthing(ILogger logger)
{
for (int i = 0; i < 10; i++)
{
logger.LogMessage("Logging a message " + i.ToString());
}
}
客户端代码如下:
// 传递文件日志记录器
DoSomthing(new FileLogger("C://LogMessage.txt"));
// txtBox是窗体上的一个文本框控件
DoSomthing(new TextBoxLogger(textBox));
但如果想同时记录到所有的日志记录器中,或者只想记录到某些日志记录器中怎么办?为了解决这个需求,创建了一个新的日志记录器,称为复合日志记录器。
// 日志记录器的复合体
class CompositeLogger : ILogger
{
private ILogger[] m_loggerArray;
// 传递ILoggers作为这个复合日志记录器的一部分
public CompositeLogger(params ILogger[] loggers)
{
m_loggerArray = loggers;
}
public void LogMessage(string strMessage)
{
// 循环遍历所有的日志记录器,并记录消息
foreach (ILogger logger in m_loggerArray)
logger.LogMessage(strMessage);
}
}
使用所有的日志记录器:
CompositeLogger compositeLogger = new CompositeLogger(
new TextBoxLogger(textBox),
new ListBoxLogger(listBox),
new FileLogger("C:\\LogPattern.txt"),
new EventLogger());
创建一个只包含TextBoxLogger和ListBoxLogger的复合日志记录器:
CompositeLogger compositeLogger = new CompositeLogger(
new TextBoxLogger(textBox),
new ListBoxLogger(listBox));
因为复合日志记录器实现了ILogger,就像所有其他日志记录器一样,可以将它传递给期望ILogger对象类型的函数。
DoSomthing(compositeLogger);
// 创建一个包含所有日志记录器的复合日志记录器
CompositeLogger compositeLogger = new CompositeLogger(
new TextBoxLogger(textBox),
new ListBoxLogger(listBox),
new FileLogger("C:\\LogPattern.txt"),
new EventLogger());
// 创建一个匿名函数来调用DoSomthing
ParameterizedThreadStart threadDelegate = delegate(object obj)
{
ILogger logger = (ILogger)obj;
DoSomthing(logger);
};
// 在线程中做一些事情
Thread t = new Thread(threadDelegate);
t.Start(compositeLogger);