最近在做一个小项目,定时计算一些金融指标。在系统运行过程中,可能会由于数据等原因出现不同的错误。但由于系统会在服务器上7*24小时运行,出现一些无关大局的错误不该影响系统计算其他指标,但必须把错误记录下来。
其实这非常容易实现,只要在出现错误的地方调用写入日志的函数即可。
但问题是,当出现错误时,错误日志不一定被写到文件中,或许会被输出到界面上的一个ListView中,甚至通过网络发送。
比如
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
if(error)
{
WriteLogToTxtFile();
WriteLogToListView();
SendLogToNet();
}
当然,这三种方式都只是假设,并且如果再增加新的方式,我可能要在所有出错的地方都增加新的函数调用。
你可能会说,写一个函数叫WriteLog(),在里面封装各个写日志的函数
像这样
1
if
(error)
2![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
3
WriteLog(string log);
4
}
5![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
void
WriteLog(
string
log)
7![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
8
WriteLogToTxtFile(log);
9
WriteLogToListView(log);
10
//当增加新的写日志方式是,在这里添加
11
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
这当然可以,但不够优雅。或许这马上让你想起了什么!对,观察者模式。
观察者模式
--
定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
其实观察者模式大多数情况下是用来处理UI操作的。比如一个按钮被点击时,N个观察者做出反应。但在这个例子中,被观察对象不再是UI控件,而是系统输出的日志。
1
Code
2
//
日志结构体
3
struct
defLogNode
4![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
5
defLogNode(COleDateTime tmDate, string szText, string szDescription)
6
:m_tmDate(tmDate),
7
m_szText(szText),
8
m_szDescription(szDescription)
9![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
10![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
}
12
COleDateTime m_tmDate;
13
string m_szText;
14
string m_szDescription;
15
}
;
16![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17
//
日志观察者基类
18
class
CLogObserverBase
19![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
20
public:
21
virtual void InsertErrorLog(defLogNode &log) = 0;
22
}
;
23![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
24
//
写入文件的观察者
25
class
CLogToFile :
public
CLogObserverBase
26![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
27
public:
28![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
CLogToFile()
{
29
m_pFile = NULL;
30
}
31
void InsertErrorLog(defLogNode & log);
32![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
private:
34
FILE *m_pFile;
35![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
36
BOOL OpenLogFile();
37
BOOL WriteLogFile(string szLog);
38
BOOL CloseLogFile();
39
}
;
40
//
在调试中写到VC输出窗口里面
41
class
CLogToDebugOutput :
public
CLogObserverBase
42![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
43
void InsertErrorLog(defLogNode & log);
44
}
;
45![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
46![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
47
class
CLogAdmin
48![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
{
49
public:
50
static copiable_ptr<CLogAdmin> GetInstance();
51
//这里使用单件模式,当需要不同种类的日志时,可以做些小的改动,用一个map管理多个SingleTon
52![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
void AddErrorObserver(CLogObserverBase * pObserver);
54![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55
void InsertOneError(defLogNode & log);
56![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
private:
58![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
CLogAdmin()
{};
59
vector<copiable_ptr<CLogObserverBase> > m_vErrorObservers;
60![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
static copiable_ptr<CLogAdmin> s_Instance;
62
//copiable_ptr是我自己写的一个引用计数的灵巧指针。如需要请留言
63
}
;
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
4
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
19
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
26
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
32
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
33
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
34
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
35
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
36
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
37
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
38
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
39
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
40
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
41
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
42
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
43
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
44
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
45
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
46
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
47
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
48
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
49
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
50
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
51
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
52
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
53
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
54
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
56
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
57
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
58
![ExpandedSubBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
![ContractedSubBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif)
![](https://www.cnblogs.com/Images/dot.gif)
59
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
60
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
61
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
62
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
63
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
这样,在系统初始化时,只需要
1
CLogAdminPtr log
=
CLogAdmin::GetInstance();
2
log
->
AddErrorObserver(
new
CLogToFile());
3
log
->
AddErrorObserver(
new
CLogToDebugOutput());
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
//
当增加一种输出方式时,只需要派生一个新的子类,并在上面代码之后加入一行
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
如果没接触过观察者模式,其实这个问题也很好理解。我们在设计面向对象程序时,总是遵循一定原则的。
首先,依赖倒置,低层结构要依赖于高层结构。在这里,调用错误日志的地方就是高层结构,而具体的方法则是低层结构。如果想文章一开始那样,则是让高层结构依赖于低层结构了,程序便出现了偶合,因为在每个地方都要知道所有写入日志的方法。
其次,单一职责,当需要记录日志的地方必须知道有哪些写入日志的方法时,便使其职责不再单一。
第三,开放封闭,开放 -- 对扩展开放;封闭 -- 对修改封闭。这里的扩展,指的就是扩展具体写日志的方法。修改,就是当增加一种写日志方法时,不该修改系统已有的程序。
其次,单一职责,当需要记录日志的地方必须知道有哪些写入日志的方法时,便使其职责不再单一。
第三,开放封闭,开放 -- 对扩展开放;封闭 -- 对修改封闭。这里的扩展,指的就是扩展具体写日志的方法。修改,就是当增加一种写日志方法时,不该修改系统已有的程序。