条款23: 宁以non-member、non-friend替代member函数
思考下面的问题:
一个网页浏览器类
class WebBrowser{
public:
...
void clearCache();//清除Cache
void clearHistory();//清除History
void removeCookies();//清除Cookies
...
};
现在用户可能还希望清除所有(以上三种),因此WebBrowser提供了这样一个函数:
class WebBrowser{
...
void clearEverything();
...
};
当然我们也可以这么做:
void clearBrowser(WebBrowser& wb)
{
wb.clearCache();
wb.clearHistory();
wb.clearCoockies();
}
现在的问题是哪个好?为什么?
首先我们讨论封装。如果某些东西被封装,他就不再可见。越多的东西被封装,越少人可以看到它,我们就有越大的弹性去改变它,因为我们的改变只会影响到那些可以直接看到改变的人。这就是我们首先推崇封装的原因:它使我们能够改变事物而只影响有限客户。
现在考虑对象里的数据。愈少的代码可以看到数据,愈多的数据被封装,而我们也就愈能自由的改变对象数据。数据被愈多的函数访问,数据的封装性就越低。
As we know,成员变量应该为private,因为如果它不是,就有无限的函数去访问它,那么它就毫无封装性。能够访问private成员只有class的member函数和friend函数。那么现在我们已经知道了,clearBrowser函数比clearEverything函数更受到欢迎,因为它具有更大的封装性。
这里有值得注意的地方,只因在意封装性而让函数“成为class的non-member”,并不意味着“不可以是另外一个class的member”。for example,我们可以让clearBrowser函数成为某个工具类的static member函数。只要它不是WebBrowser的一部分(或成为其friend),就不会影响WebBrowser的private成员的封装性。
在C++中,我们可以这样做
namespace WebBrowserStuff{
class WebBrowser{...};
void clearBrowser(WebBrowser& wb);
...
}
对于namespace,它与class不同,前者可以跨越多个头文件,为了方便我们可以定义多个头文件:
//头文件 "webbrowser.h" -----这个针对class WebBrowser本身及WebBrowser的核心机能。
namespace WebBrowserStuff{
class WebBrowser{...};
...
}
//头文件 "webbrowserbookmarks.h"
namespace WebBrowserStuff{
...
}
//头文件 "webbrowsercookies.h"
namespace WebBrowserStuff{
...
}
...
将便利函数放在多个头文件内但是属于同一个名字空间,意味着客户可以轻松扩展这组便利函数。