本条款强调封装性优先于类的内聚逻辑
看书上的例子:
class WebBrower
{
public: void ClearCach();
void ClearHistory();
void RemoveCookies();
};
定义了一个WebBrowser类, 在类里面执行清理缓存, 清历史记录和清理cookies. 如果将这三个小函数写进一个函数里面, 那么这个大函数放在类内还是类外呢?
(cookie是操作系统三级存储系统中的一级,三级存储系统包括cookie,内存,硬盘。缓存只是在内存中开辟的空间,不是一个概念)
- 放在类内:
class WebBrower
{
....
void ClearEverything()
{
public: void ClearCache();
void ClearHistory();
void RemoveCookies();
}
....
};
- 放在类外:
void ClearWebBrowser(WebBrowser& web)
{
web.ClearCache();
web.ClearHistory();
web.RemoveCookies();
}
根据面向对象的基本概念, 应该把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象. 这就意味着我们应该把它放在类内里面, 然而, 如果从封装性上看, 这个大函数应该放在类外。
-
如果位于类内: 意味着这个函数除了访问到这三个小的清理函数之外, 还可以访问到类内的私有成员. 随着产品功能的扩充, 这个函数很可能逐渐丰富起来, 越丰富就说明封装行越差, 一旦功能发生变更, 改动的地方会很大.
-
如果放在类外, 通过传入WebBrowser的对象来对类的public函数进行访问的, 这个函数是不可能访问private成员变量的. 因此放在类外的封装性会强于放在类内. 要注意一点, 类外的
ClearWebBrowser不能是WebBrower的友元函数, 因为友元函数可以直接访问类的private和protect成员变量.
把这个清除的函数放在类外, 并不能破坏和类内的关联, 书上提供了namespace解决方案, eg:
namespace WebBrowserStuff
{
…
class WebBrowser();
void ClearWebBrowser(WebBrowser& w);
…
}
namespace和class不同, namespace可以跨越多个源码文件后者并不能. namespace是开放的,和class不同的是你可以在多个文件里面象同一个namespace里面添加东西。比如stl里面的东西都是在名字空间std里面,但是却定义在了多个文件里面。命名空间的捆绑, 是在封装和内聚之间很好的平衡.
最后我们总结一下这个遵循这个条款的好处
- 1.增加代码的封装性
- 2.提高代码的扩展性
- 3.降低代码的编译依存性。