從一個網上找的例子說起:
定義了一個ILog接口,用於記錄日誌文件,它有一個對外接口WriteLog用於記錄日誌
這些日誌可以記錄到磁盤上(FileLog)或者數據庫上(DBLog),或者其它的什麼地方;後來,你又發現需要一個StdOutLog,於是你又繼承了一個StdOutLog類。
各種派生類:DBLog, FileLog, StdOutLog不同的Log創建不同的對象。但對於程序來說他們都是ILog,程序中使用該日誌功能的方法都是ILog->WriteLog(),對於日誌類的不同具體實現不影響你客戶端的已有代碼。
版本一
1、如果我們用面向過程的方法,直接針對不同的實現都分別寫一個write函數,eg:void write_dblog()
2、接着,用戶要求改用文件來實現,你又得寫一個write_filelog()函數,關鍵是接下來你得把客戶端程序中所有調用write_dblog的代碼都改成write_filelog()
3、對於write_stdoutlog同樣是上面的問題
版本二
這下,我們感覺相當的不爽,改成用宏定義來實現
#define write_log write_stdoutlog
好了,以後再怎麼改,我們的程序只需要修改宏就好了。
版本三
過了一段時間,用戶老是要頻繁的修改記錄方式,每次修改宏定義後,我們又要重新編譯,
爲了避免重新編譯,我們現在改用dll。我們把不同寫日誌的函數都叫做 write_log,然後不同的dll(db.dll,file.dll,stdout.dll)根據不同需要去實現write_log函數
最後,我們把write_log 這個函數導出。這樣以來,每次用戶要更改記錄方式的時候,我們可以直接根據需要去替換這個dll庫,而不用重新修改甚至重新編譯用戶的代碼。
(感嘆dll的神奇和偉大)
版本四:
又過了一段時間,用戶又提出了許多需求, 我們把他們叫做:function1(),function2(),function3()......function100()
這下麻煩了,由於使用dll,我們需要導出dll中的函數,並用指向函數的指針來記錄他們,100個需求對應100個函數,都要我們在用戶程序中用指針的方式記錄下來,對於這個工作量 我只能表示"呵呵"。
好了,接着改。用面向對象的方法來解決:
創建一個接口
class ILog
{
virtual void write_log() = 0;
virtual void function1() = 0;
virtual void function2() = 0;
...
virtual void function100() = 0;
};
然後在DB.dll和 File.dll中,實現這個接口
class DBLog : public ILog
{
virtual void write_log() {.....};
virtual void function1() {...};
virtual void function2() {...};
...
virtual void function100() {.....};
};
class FileLog : public ILog
{
virtual void write_log() {.....};
virtual void function1() {...};
virtual void function2() {...};
...
virtual void function100() {.....};
};
最後,你再讓這些dll文件只導出一個獲取具體實現類的接口: ILog * create_log_object();
,這樣用戶程序裏只需要保存一個,ILog * pLog 類型的指針。
其他的地方只需要寫pLog->write_log() 、pLog->function1() 。。。。。,看到沒有這樣用戶代碼段裏就不需要再去記錄100多個函數指針了。我們程序的靈活性進一步提高!!!!!