Log的输出问题是程序设计需要在设计初期就要计划的一个模块,其接口和功能的设计,会直接影响整体程序的调试和信息输出等方面。
wxDeMPQ在初期,计划通过其StatusBar作为Log输出,并简单封装了一个函数,但在实际使用中,由于急于实现功能和DLL等的引入,加上VC方便的调试,导致完全废弃了当初的想法,这也是的wxDeMPQ在后期实现上没有任何的Log输出,这对于Debug的程序来说,是--灾难和活该。
对于类似Log输出的模块,在实现时需要考虑的是使用时的易融合性和灵活性。简单地说,一来此模块的引入不应影响原代码的执行;二来要考虑信息输出的不确定性,就是说你可能无法预知程序会最终通过什么方式输出,文件?Console?或者一个EditCtrl?这两点我认为是需要在初期着重考虑的。
下面是一个简单Log输出模块的实现,通过Adapter方式,连接输入和输出。
#pragma once
#include <string>
#ifdef OUTPUTAGENTLIBRARY_EXPORTS
#define OUTPUTAGENTLIBRARY_API __declspec(dllexport)
#else
#define OUTPUTAGENTLIBRARY_API __declspec(dllimport)
#endif
namespace OUTPUT
{
class OUTPUTAGENTLIBRARY_API COutputBase
{
public:
COutputBase() {}
virtual ~COutputBase() {}
virtual void Output(const std::wstring& info) = 0;
};
const unsigned int LEVEL_DEBUG = 1;
const unsigned int LEVEL_INFO = 2;
const unsigned int LEVEL_WARN = 4;
const unsigned int LEVEL_ERROR = 8;
const unsigned int LEVEL_ALL = 0xFFFFFFFF;
class OUTPUTAGENTLIBRARY_API COutputAgentObject
{
public:
COutputAgentObject();
virtual ~COutputAgentObject();
void SetLevel(unsigned int level);
unsigned int GetLevel() const;
void SetOutput(COutputBase* output);
COutputBase * GetOutput() const;
void Output(unsigned int level, const std::wstring& info);
protected:
COutputBase* _output;
unsigned int _level;
};
}
//#define OUTPUT(outputptr, level, info) \
//{\
// if(outputptr != NULL) \
// {\
// std::wostringstream ostr; \
// ostr << info; \
// outputptr->Output(level, ostr.c_str()); \
// }\
//}
#include "stdafx.h"
#include "OutputAgentObject.h"
namespace OUTPUT
{
COutputAgentObject::COutputAgentObject()
: _output(NULL), _level(LEVEL_ALL)
{
}
COutputAgentObject::~COutputAgentObject()
{
}
void COutputAgentObject::SetLevel(unsigned int level)
{
_level = level;
}
unsigned int COutputAgentObject::GetLevel() const
{
return _level;
}
void COutputAgentObject::SetOutput(COutputBase* output)
{
_output = output;
}
COutputBase* COutputAgentObject::GetOutput() const
{
return _output;
}
void COutputAgentObject::Output(unsigned int level, const std::wstring& info)
{
if(_output == NULL)
return;
if((level & _level) == 0)
return;
_output->Output(info);
}
}
下面是一段测试代码,用于展示如何使用。
#pragma once
#include <string>
#include <sstream>
#include "wx/wx.h"
#include "OutputAgentObject.h"
class COutput : public OUTPUT::COutputBase
{
public:
COutput(wxTextCtrl* text)
:_text(text)
{
}
virtual ~COutput() {}
virtual void Output(const std::wstring& info)
{
if(_text != NULL)
{
_text->AppendText(WString2wxString(info));
}
}
protected:
const wxString WString2wxString(const std::wstring& str)
{
return wxString(str.c_str(), wxConvISO8859_1);
}
private:
wxTextCtrl* _text;
};
OUTPUT::COutputAgentObject g_stOutputAgent;
#define OUTPUT(level, info) \
{\
std::wostringstream ostr; \
ostr << info; \
g_stOutputAgent.Output(level, ostr.str());\
}
_output = new COutput(m_textOutput);
g_stOutputAgent.SetOutput(_output);
OUTPUT(OUTPUT::LEVEL_INFO, L"Level:" << g_stOutputAgent.GetLevel() << std::endl);
简单实现,很多因素并不考虑,如Thread Safe问题等,源码和测试代码在
这里。测试程序模样如下: