利用Observer(觀察者)模式實現系統日誌

來源:互聯網
上載者:User

最近在做一個小項目,定時計算一些金融指標。在系統運行過程中,可能會由於資料等原因出現不同的錯誤。但由於系統會在伺服器上7*24小時運行,出現一些無關大局的錯誤不該影響系統計算其他指標,但必須把錯誤記錄下來。

其實這非常容易實現,只要在出現錯誤的地方調用寫入日誌的函數即可。

但問題是,當出現錯誤時,錯誤記錄檔不一定被寫到檔案中,或許會被輸出到介面上的一個ListView中,甚至通過網路發送。

比如

Code
if(error)
{
    WriteLogToTxtFile();
    WriteLogToListView();
    SendLogToNet();
}

當然,這三種方式都只是假設,並且如果再增加新的方式,我可能要在所有出錯的地方都增加新的函數調用。

你可能會說,寫一個函數叫WriteLog(),在裡面封裝各個寫日誌的函數

像這樣

 

 1if(error)
 2{
 3    WriteLog(string log);
 4}
 5
 6void WriteLog(string log)
 7{
 8    WriteLogToTxtFile(log);
 9    WriteLogToListView(log);
10    //當增加新的寫日誌方式是,在這裡添加
11}

 

這當然可以,但不夠優雅。或許這馬上讓你想起了什麼!對,觀察者模式。

 

觀察者模式--

      定義對象間一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都得到通知並被自動更新。

 

其實觀察者模式大多數情況下是用來處理UI操作的。比如一個按鈕被點擊時,N個觀察者做出反應。但在這個例子中,被觀察對象不再是UI控制項,而是系統輸出的日誌。

 

 1Code
 2//日誌結構體
 3struct defLogNode
 4{
 5    defLogNode(COleDateTime tmDate, string szText, string szDescription)
 6        :m_tmDate(tmDate),
 7        m_szText(szText),
 8        m_szDescription(szDescription)
 9    {
10
11    }
12    COleDateTime m_tmDate;
13    string         m_szText;
14    string         m_szDescription;
15};
16
17//日誌觀察者基類
18class CLogObserverBase
19{
20public:
21    virtual void InsertErrorLog(defLogNode &log) = 0;
22};
23
24//寫入檔案的觀察者
25class CLogToFile : public CLogObserverBase
26{
27public:
28    CLogToFile(){
29        m_pFile = NULL;
30    }
31    void InsertErrorLog(defLogNode & log);
32
33private:
34    FILE *m_pFile;
35
36    BOOL OpenLogFile();
37    BOOL WriteLogFile(string szLog);
38    BOOL CloseLogFile();
39};
40//在調試中寫到VC輸出視窗裡面
41class CLogToDebugOutput : public CLogObserverBase
42{
43    void InsertErrorLog(defLogNode & log);
44};
45
46
47class  CLogAdmin  
48{
49public:
50    static copiable_ptr<CLogAdmin> GetInstance();
51//這裡使用單件模式,當需要不同種類的日誌時,可以做些小的改動,用一個map管理多個SingleTon
52
53    void AddErrorObserver(CLogObserverBase * pObserver);
54
55    void InsertOneError(defLogNode & log);
56
57private:
58    CLogAdmin(){};
59    vector<copiable_ptr<CLogObserverBase> > m_vErrorObservers;
60
61    static copiable_ptr<CLogAdmin> s_Instance;
62//copiable_ptr是我自己寫的一個引用計數的靈巧指標。如需要請留言
63};

 

這樣,在系統初始化時,只需要

 

1    CLogAdminPtr log = CLogAdmin::GetInstance();
2    log->AddErrorObserver(new CLogToFile());
3    log->AddErrorObserver(new CLogToDebugOutput());
4
5//當增加一種輸出方式時,只需要派生一個新的子類,並在上面代碼之後加入一行

 

如果沒接觸過觀察者模式,其實這個問題也很好理解。我們在設計物件導向程式時,總是遵循一定原則的。

 

首先,依賴倒置,低層結構要依賴於高層結構。在這裡,調用錯誤記錄檔的地方就是高層結構,而具體的方法則是低層結構。如果想文章一開始那樣,則是讓高層結構依賴於低層結構了,程式便出現了偶合,因為在每個地方都要知道所有寫入日誌的方法。

其次,單一職責,當需要記錄日誌的地方必須知道有哪些寫入日誌的方法時,便使其職責不再單一。

第三,開放封閉,開放--對擴充開放;封閉--對修改封閉。這裡的擴充,指的就是擴充具體寫日誌的方法。修改,就是當增加一種寫日誌方法時,不該修改系統已有的程式。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.