struct IWriter : public IRefCount; <!--[if !supportEmptyParas]--> class Writer : public IWriter; 現在來考慮Writer的實現,和Reader一樣,Writer除了要實現IWriter的接口外,同時還需要實現IRefCount的接口。現在,我們來看看IRefCount是如何定義的:
class HeaPReader : IReader; class StackReader : HeapReader{ virtual void dispose() { } }; 問題是,StackReader 是一個HeapReader嗎?為了代碼復用,我們完全不管什么概念了。當然,假如你和我一樣,看重維護概念,那么這么實現吧:
class HeapReader : IReader; class StackReader : IReader; 這樣一來,IReader的實現將被重復,又違反了DRY原則,等著被將來維護的工程師詛咒吧!或許,那個維護工程師就是3個月后的你自己。假如這樣真的能夠解決問題,那么也還是可以接受的,很快,我們有了一個新的接口:
struct IRWiter : IReader, IWriter; class RWiter : public IRWiter; 考慮一下IRefCount的語義:它用來記錄對所在對象的引用計數。很顯然,我從IReader和IWriter中的任意一個分支獲得的IRefCount應該都是獲得一樣的引用計數效果。但是現在,這個繼續樹存在兩個IRefCount的實例,我們不得不在RWiter當中重新重載一遍。這樣,從IReader和IWriter繼續來的兩個實例就作廢了,而且,我們可能還浪費了8個字節。為了解決這個問題,我們還可以在另一條危險的道路上繼續前進,那就是虛擬繼續:
struct IReader : virtual public IRefCount; struct IWriter : virtual public IRefCount; 還記得大師們給予的忠告嗎--“不要在虛基類中存放數據成員”。“這樣有什么問題嗎,我們不必對大師盲目崇拜”,你一定也聽過這樣的建議。假如大師們不能說服這些人,那么我也不能。于是,我們進一步在所有的接口中提供默認實現,包括IReader和IWriter.
template<typename Base> class ImpHeapRefCount : public Base{ constraint(is_base_derive(IRefCount, Base)); ..}; 類似的:
template<typename Base> class ImpStackRefCount : public Base; <!--[if !supportEmptyParas]--> template<typename Base> class ImpPoolRefCount : public Base; <!--[endif]--> 再看看,我們如何實現所有的Reader.