惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The GitHub Blog
The GitHub Blog
MyScale Blog
MyScale Blog
爱范儿
爱范儿
GbyAI
GbyAI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
美团技术团队
Y
Y Combinator Blog
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
Martin Fowler
Martin Fowler
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
M
MIT News - Artificial intelligence
博客园 - Franky
V
Visual Studio Blog
I
InfoQ
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
腾讯CDC
博客园 - 司徒正美
L
LangChain Blog

博客园 - 海阔天

【原创】Self-Contained Container(自包含容器) Kindle 转换器 Win32 多线程学习笔记 海天软件自动安装工具 cd /d %~dp0是什么意思啊? (转)STL vector 容器介绍 . 【转】在VC++下实现高彩色工具条2011-05-19 14:35引言 vc编译错误pass it through SDKPAINT的处理方法 [转]修改SDI主窗口Title (转)VC中让CListBox带有复选框 (转)电脑程序员才能看懂的笑话 (转)专业的程序员需要具备的思考能力:写一个程序需要注意多少细节问题 (转)另一篇:VC导出数据到EXCEL (转)我的10个开发原则 [转]STL中map用法详解 [转]创业前应先做出一个好的非盈利产品 单元测试 版本控制 VC编程心得
(原创)日志处理(修改)
海阔天 · 2011-08-13 · via 博客园 - 海阔天

日志处理

日志可能有多种形式,比如以文件存储,显示到控制台屏幕上,或者在程序的一个列表框中……我们可以定义一个日志基类,然后继承之,针对不同的情况设计不同的子类。但如果程序中要求既在程序列表里显示日志,又要记录到文件或者还要记录到数据库等等吧,那么写日志的代码就非常麻烦,要几个日志类重复同样的动作。

利用下面的思路可以解决这个问题,在代码中只需要一个类的一个方法,就可以搞定所有日志类写日志的动作,同时又能起到一定的注释作用,是不是非常好!

OK! Let's go!

首先,定义一个日志类接口,主要给不同情况下生成日志的时候用。比如有的程序在自己的界面列表上输出日志,那么就可以实现这个接口,然后把实现的类传递到CLogHelper对象中,CLogHelper负责用日志接口列表中的日志接口写日志操作,而实现ILog接口的类负责实现日志的真实写入操作。

以下(核心)代码在VC6下编译并测试通过。代码中使用了STL技术。下同。

MyInterface ILog  
{
public:
    ILog();
    
virtual ~ILog();virtual void write(string logMsg);
    
virtual void writeLn(string logMsg);void debugWrite(string logMsg);
    
void debugWriteLn(string logMsg);
};

MyInterface 是自己定义的一个接口,按照园子里的方法如下:

#define MyInterface class __declspec(novtable)

CLogHelper类是日志类的助手,可以添加日志对象(ILog类型),提供每个日志对象的写日志功能。它也可以继承ILog接口。

class CLogHelper : public ILog  
{
public:
    CLogHelper();
    
virtual ~CLogHelper();void write(string logMsg);
    
void writeLn(string logMsg);// 下面的方法用于DEBUG环境
    void debugWrite(string logMsg);
    
void debugWriteLn(string logMsg);
    
    
void add(ILog *log);
    
private:
    list
<ILog *> logs;
};

CLogHelper::CLogHelper()
{

}

CLogHelper::

~CLogHelper()
{
    logs.clear();
}
void CLogHelper::write(string logMsg)
{
    list
<ILog *>::iterator logi;
    
for(logi=logs.begin();logi!=logs.end();logi++)
        (
*logi)->write(logMsg);
}
void CLogHelper::writeLn(string logMsg)
{
    
string msg=logMsg+"\n";
    write(msg);
}
void CLogHelper::add(ILog *log)
{
    logs.push_back(log);
}
void CLogHelper::debugWrite(string logMsg)
{
#ifdef _DEBUG
    write(logMsg);
#endif
}
void CLogHelper::debugWriteLn(string logMsg)
{
    
string msg=logMsg+"\n";
    debugWrite(msg);
}

下面是具体的日志类,它们都继承ILog接口。包括写入文件的日志类,控制台显示的日志类、程序列表中用到的日志类等等。

比如定义写入文件的日志类CLog继承ILog接口,代码略。

然后提供一个Log构建器(CLogBuilder),里面包括所有的具体日志类,在构造函数里把具体的日志类添加到CLogHelper中。构造函数提供一个文件路径的参数,表示文件日志要写到什么地方。这个参数默认为mylog.log文件,表示写到程序所在目录下,文件名默认为"mylog.log"。构造函数提供另一个参数为CLogHelper,就是说CLogHelper类是从外部传入的。

class CLogBuilder  
{
public:
    CLogBuilder(CLogHelper 
*logHelper,string path="mylog.log");
    
virtual ~CLogBuilder();string m_Path;
    
    CLog 
*fileLog;
};

CLogBuilder::CLogBuilder(CLogHelper 

*logHelper,string path)
:fileLog(
0),m_Path(path)
{
    fileLog
=new CLog(m_Path.c_str());
    
    
// 向LogHelper中添加日志类
    logHelper->add((ILog *)fileLog);
}

CLogBuilder::

~CLogBuilder()
{
    
if(fileLog)
    {
        delete(fileLog);
        fileLog
=NULL;
    }
}

然后定义一个职责转义类,在其它的类中需要提供写日志的时候,用这个类(定名为CRemark)。如果每个类的每个方法里都有写日志的代码,会把代码搞的很混乱,不突出方法的主题,也好像这个方法完成多项任务似的,代码不简明。记得VC的注释代码中有“// todo :”,所以这个类提供一个方法叫toDo(),其参数就是toDO()语句以下代码所完成工作的内容描述。看起来,这个方法好像是在给代码作注释。这样既起到了注释的作用,同时在toDo()方法中还可以调用日志类去写日志,岂不是一举两得。因为这个类在代码中看只是起到注释的作用,而在它的方法中却转义成了写日志,所以称其为职责转义类。当然,如果你发现这个类还可以干其它的事情,请你一定告诉我。

class CRemark  
{
public:
    CRemark();
    
virtual ~CRemark();

    CLogHelper 

*logHelper;
    CLogBuilder 
*logBuilder;
    
    
void toDo(string comment,BOOL isDebug=FALSE);
};

CRemark::CRemark()
:logHelper(

0),logBuilder(0)
{
    logHelper
=new CLogHelper();
    logBuilder
=new CLogBuilder(logHelper);
}

CRemark::

~CRemark()
{
    
if(logHelper)
    {
        delete(logHelper);
        logHelper
=NULL;
    }
    
if(logBuilder)
    {
        delete(logBuilder);
        logBuilder
=NULL;
    }
}
void CRemark::toDo(string comment,BOOL isDebug)
{
    
if(isDebug)
        logHelper
->debugWriteLn(comment);
    
else
        logHelper
->writeLn(comment);
}

代码比较完美和优雅了,就像C#那样,嘻嘻!

可以这样使用:

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CRemark mark;
    mark.toDo(
"嘻嘻哈哈吼吼!");

  //这里是程序中实际的代码


    mark.toDo(
"DEBUG版本显示。。。",TRUE);

  //这里是程序中实际的代码

    mark.toDo("GOOD JOB!");

  //这里是程序中实际的代码

    system(
"pause");

}


程序会在所在目录下创建(默认)mylog.log文件,并在其中显示三行文本;如果改成Release,则只输出两行文本。