天天看點

EffectiveC++學習筆記-條款22|23

條款22 将成員變量聲明為private

注意一點protected并不比public更具有封裝性

條款23 使用non-member、non-friend替換member函數

總結一下書上講的:

class WebBrowser
{
public:
    ...
    void clearCache();
    void clearHistory();
    void removeCookies();
    ...
}
//執行這些操作可以提供一個成員函數
void clearEverything();//調用個函數
//或者提供一個非成員函數
void clearBrowser(WebBrowser& wb);//調用個函數
           

書上選擇了第二個并且給出了比較好的方案:

namespace WebBrowserStuff{
    class WebBrowser{...};
    void clearBrowser(WebBrowser& wb);
    ...
}
           

根據面向對象守則的要求,資料以及操作資料的函數應該捆綁在一起,都放在類中,這意味着把它放在類内會比較好。但從封裝性的角度而言,它卻放在類外好,為什麼?

為了區分開,我們把在類内的總清除函數稱之為ClearEverything,而把類外的總清除函數稱之為ClearWebBrower。ClearEverything對封裝性的沖擊更大,因為它位于類内,這意味着它除了通路這三個公有函數外,還可以通路到類内的私有成員,是的,你也許會說現在這個函數裡面隻有三句話,但随着功能的擴充,随着程式員的更替,這個函數的内容很可能會逐漸“豐富”起來。而越“豐富”說明封裝性就會越差,一旦功能發生變更,改動的地方就會很大。

再回過頭來看看類外的實作,在ClearWebBrowser()裡面,是通過傳入WebBrower的形參對象來實作對類内公有函數的通路的,在這個函數裡面是絕對不會通路到私有成員變量(編譯器會為你嚴格把關)。是以,ClearWebBrowser的封裝性優于類内的ClearEverything。

但這裡有個地方需要注意,ClearWebBrower要是類的非友元函數,上面的叙述才有意義,因為類的友元函數與類内成員函數對封裝性的沖擊程度是相當的。

看到這裡,你也許會争辯,把這個總清除的功能函數放在類外,就會割離與類内的關聯,邏輯上看,這個函數就是類内函數的組合,放在類外會降低類的内聚性。

為此,書上提供了命名空間的解決方案,事實上,這個方案也是C++标準程式庫的組織方式,好好學習這種用法很有必要!

namespace與class不同,前者可以跨越多個源碼檔案,而後者不能。通過命名空間的捆綁,是在封裝和内聚之間非常好的平衡。

最後總結一下,本條款強調封裝性優先于類的内聚邏輯,這是因為“愈多東西被封裝,愈少人可以看到它,而愈少人看到它,我們就有愈大的彈性去改變它,因為我們的改變僅僅影響看到改變的那些人或事物”。采用namespace可以對内聚性進行良好的折中。

繼續閱讀