假如有一个以下的类,用来表示网页浏览器,其中有一些函数用来清除下载元素高速缓冲区、清楚访问过的URLs的历史记录、以及移除系统中的所有cookies:
class WebBroswer
{
public:
...
void clearCache();
void clearHistory();
void removeCookies();
...
};
许多用户想一次性执行所有这些动作,因此WebBroswer提供这样一个函数:
class WebBroswer
{
public:
...
void clearEverything();//调用clearCache,clearHistory,removeCookies
...
};
当然,我们也可以提供一个非成员函数:
void clearBrowser(WebBrowser & wb)
{
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
现在问题来了:哪一个比较好呢?是成员函数还是非成员函数?
面向对象守则要求数据一个尽可能被封装,成员函数提供clearEverything
带来的封装性比非成员函数clearBrowser
低。此外提供非成员函数可允许堆WebBrowse
相关技能有较大的包裹弹性,因为这会导致相对较低的编译相依度,增加WebBrowser
的可延伸性.
原因如下:
如果某些东西被封装,它就不可见,越多东西被封装,越少人可以看到它。而越少人看到它,我们就有越大的空间去变化它。因为我们的改变仅仅影响到那些看到改变的那些人和事物。也就是说,越多东西被封装,我们改变那些东西的能力越大,这就是我们推崇封装的原因。
考虑对象内的数据,越少代码可以看到数据,越多的数据被封装,我们就越能自由地改变对象数据。那如何判断一个数据的封装性呢?
可以计算能够访问该数据的函数数量,作为一个粗糙的量测。越多函数可以访问它,数据的封装性就越低。
如果你在一个成员函数和一个非成员,非友元函数之间,两者提供相同的功能,那么导致较大封装性的是非成员非友元函数,因为它并不增加"能够访问类内私有成分"的函数数量。这就解释了为什么clearBrowse
比clearEverything
更好的原因:它导致WebBrowse class有较大的封装性
注意:
因为封装性而让函数成为类的非成员函数并不意味着它不可用是另外一个类的成员。 比如我们可以让clearBrowser
成为工具类的静态成员函数,只要它不是WebBrowse
的一部分就不会影响WebBrowse
的私有成员封装性.
在C++里面,比较自然的做法是让clearBrowser
成为一个非成员函数并且位于和WebBrowse
同一个命名空间内:
namespace WebBrowserStuff
{
class WebBrowser{...};
void clearBrowser(WebBrowser & wb);
}
总结:
宁可拿non-member non-friend函数替换member函数。这样可以增加封装性、包裹弹性和机能扩充性。