装饰模式(Decorator pattern)应用----日志信息输出
装饰模式解释:装饰模式可以动态地给一个对象添加一些额外的职责,而不用修改已有的类(设计模式—可复用面向对象软件的基础
(P115)
)。
在软件的开始过程中,经常需要记录一下日志信息。日志信息一般都是一些调试信息、出错信息或者程序的执行流程输出。
日志信息有各种不同的输出方式:如输出到文件,输出到控制台,输出到数据库,输出到 Output 窗口(VC中),或者它们之间的任意组合(既要输出到文件又要输出到控制台等)等等。
日志信息在输出之间可能要做一些处理:如对日志信息进行压缩存储,对日志信息进行加密存储,诸如此类。
日志信息可能要根据不同的严重级别或者不同的分类进行选择性的输出。如比较严重的出错可能要求在任何情况下都要输出,有的日志信息可能只作为诊断之用,在要诊断的时才要求输出。
上述各每一项都可以改变,如增加输出方式,增加压缩方式等。
采用装饰模式(
Decorator pattern
)可以实现这个需求。
一、类的组织结构图
类的组织结构图如下图所示:
二、各个类说明:
wgxLogInterface
:定义
log
各接口
wgxLog
:被修饰的
log
对象
wgxLogDecorator
:用来修饰对象接口
wgxFileLog
:把
log
输出到文件
wgxConsoleLog
:把
log
输出到控制台
wgxFilterLog
:对输出的
log
进行过滤操作,不符合条件的
log
不输出
wgxLogMsg
:要输出的
log
信息
三、具体实现:
创建一个
LogLib
工程,专门用于日志信息的输出,别的工程要用到日志信息输出时,只要链接
LogLib
即可。
1、类 wgxLogMsg:
class wgxLogMsg
{
private:
string m_strMsg; //
要输出的日志内容
public:
wgxLogMsg(const char *pszMsg);
const char *GetMsg() const { return m_strMsg.c_str(); }
};
wgxLogMsg::wgxLogMsg(const char *pszMsg)
{
m_strMsg = pszMsg;
}
2、类 wgxLogInterface
class wgxLogInterface
{
public:
virtual void Log(int nPassport, const wgxLogMsg &msg) = 0;
};
3、类 wgxLog
class wgxLog : public wgxLogInterface
{
public:
void Log(int nPassport, const wgxLogMsg &msg);
};
void wgxLog::Log(int nPassport, const wgxLogMsg &msg)
{
}
4、类 wgxLogDecorator
class wgxLogDecorator : public wgxLogInterface
{
protected:
wgxLogInterface *m_pLog;
public:
wgxLogDecorator(wgxLogInterface *pLog);
virtual void Log(int nPassport, const wgxLogMsg &msg);
};
wg xLogDecorator::wgxLogDecorator(wgxLogInterface *pLog) : m_pLog(pLog)
{
}
void wgxLogDecorator::Log(int nPassport, const wgxLogMsg &msg)
{
m_pLog->Log(nPassport, msg);
}
5、类 wgxFileLog
class wgxFileLog : public wgxLogDecorator
{
private:
string m_strLogFile; //
接受日志信息的文件名
public:
wgxFileLog(wgxLogInterface *pLog, const char *pszFileName);
void Log(int nPassport, const wgxLogMsg &msg);
};
wgxFileLog::wgxFileLog(wgxLogInterface *pLog, const char *pszFileName) : wgxLogDecorator(pLog)
{
m_strLogFile = pszFileName;
}
void wgxFileLog::Log(int nPassport, const wgxLogMsg &msg)
{
FILE *pf = fopen(m_strLogFile.c_str(), "a");
if (pf)
{
//
输出日志信息到文件中
fprintf(pf, "%s", msg.GetMsg());
fclose(pf);
return;
}
wgxLogDecorator::Log(nPassport, msg);
}
6、类 wgxConsloeLog
class wgxConsoleLog : public wgxLogDecorator
{
public:
wgxConsoleLog(wgxLogInterface *pLog);
void Log(int nPassport, const wgxLogMsg &msg);
};
wgxConsoleLog::wgxConsoleLog(wgxLogInterface *pLog) : wgxLogDecorator(pLog)
{
}
void wgxConsoleLog::Log(int nPassport, const wgxLogMsg &msg)
{
//
输出到控制台
cout<<msg.GetMsg();
wgxLogDecorator::Log(nPassport, msg);
}
7、类 wgxFilterLog
const int PASSPORT_MAX = 0xff; // 最多记录 0xff 个通行证号
class wgxFilterLog : public wgxLogDecorator
{
private:
int m_nPassport[PASSPORT_MAX]; //
可以通过的通行证(
0
表示此位置上没有记录通行证号)
public:
wgxFilterLog(wgxLogInterface *pLog);
void Log(int nPassport, const wgxLogMsg &msg);
//
注册通行证
void RegisterPassport(int nPassport);
//
注销通行证
void UnregisterPassport(int nPassport);
protected:
//
通行证是否可以通过
bool CanPass(int nPassport);
//
查找通行证所在的位置
int FindPassport(int nPassport);
//
找一个空位置
int FindFreePos();
};
wgxFilterLog::wgxFilterLog(wgxLogInterface *pLog) : wgxLogDecorator(pLog)
{
memset(m_nPassport, 0, sizeof (m_nPassport));
}
void wgxFilterLog::Log(int nPassport, const wgxLogMsg &msg)
{
if (! CanPass(nPassport))
//
此通行证号不能通过
return;
wgxLogDecorator::Log(nPassport, msg);
}
void wgxFilterLog::RegisterPassport(int nPassport)
{
int nPos = FindPassport(nPassport);
if (nPos != PASSPORT_MAX)
//
已经注册过,不需要再注册
return;
nPos = FindFreePos();
if (nPos == PASSPORT_MAX)
//
已经没有空位置可以存放另外的通行证
return;
m_nPassport[nPos] = nPassport;
}
void wgxFilterLog::UnregisterPassport(int nPassport)
{
int nPos = FindPassport(nPassport);
if (nPos == PASSPORT_MAX)
//
此通行证没注册过
return;
//
注销通行证
m_nPassport[nPos] = 0;
}
bool wgxFilterLog::CanPass(int nPassport)
{
return FindPassport(nPassport) != PASSPORT_MAX;
}
int wgxFilterLog::FindPassport(int nPassport)
{
int i = 0;
for (; i < PASSPORT_MAX; i++)
if (m_nPassport[i] == nPassport)
//
找到通行证所在的位置
break;
return i;
}
int wgxFilterLog::FindFreePos()
{
return FindPassport(0);
}
四、
实际应用:
#include "../LogLib/FileLog.h"
#include "../LogLib/ConsoleLog.h"
#include "../LogLib/Log.h"
#include "../LogLib/FilterLog.h"
#include "../LogLib/LogMsg.h"
#include <map>
#include <string>
using namespace std;
// 自定义 map
class wgxMap
{
public:
map<string, string> m_Map;
//
自定义
map
转化为
wgxLogMsg
operator wgxLogMsg()
{
#define INI_MAP(str) m_Map[str] = str;
INI_MAP("1");
INI_MAP("1");
INI_MAP("2");
INI_MAP("3");
INI_MAP("4");
INI_MAP("5");
//
输出测试代码
string str = "";
for (map<string, string>::iterator iter = m_Map.begin(); iter != m_Map.end(); iter++)
{
str += (*iter).first;
str += "=";
str += (*iter).second;
str += "/n";
}
return wgxLogMsg(str.c_str());
}
};
int _tmain(int argc, _TCHAR* argv[])
{
//
对日志信息输出进行装饰
wgxLog *pLogger = new wgxLog;
wgxFileLog *pFileLog1 = new wgxFileLog(pLogger, "d:/log1.txt"); //
输出到
d:/log1.txt
wgxFileLog *pFileLog2 = new wgxFileLog(pFileLog1, "d:/log2.txt"); //
输出到
d:/log2.txt
wgxConsoleLog *pConsoleLog = new wgxConsoleLog(pFileLog2); //
输出到控制台
wgxFilterLog *pFilterLog = new wgxFilterLog(pConsoleLog); //
输出过滤操作
//
输出测试
wgxMap mapping;
pFilterLog->RegisterPassport(1); //
注册通行证号
1
pFilterLog->Log(1, mapping); //
输出
map
pFilterLog->Log(1, "²âÊÔ´úÂë/n"); //
输出字符串
// 删除装饰
delete pFilterLog;
delete pConsoleLog;
delete pFileLog2;
delete pFileLog1;
delete pLogger;
getchar();
return 0;
}
五、 相关说明:
1
、所有的
wgxLogDecorator
都用来修饰
wgxLog
,但是
wgxLog
本身并没有做任何操作;
2
、输出
log
的接口函数
Log
都带有一个参数
nPassport
是为了过滤之用,目前仅在
wgxFilterLog
中有用到这个参数。
3
、
wgxLogMsg
只封装了
string
,可以考虑封装要输出的内存。
4
、可以把任意要输出的类型转化成
wgxLogMsg
进行输出(具体参考实际实用);
5
、输出日志信息之前可以对要输出的信息进行压缩、加密等操作,只要被要相应的
decorator
即可。
需要完整源码的请留下e-mail