为耦合辩护,为继承伸冤
大家都听说过,有个称号叫“基于对象”,用来授予那些
没有资格获得“面向对象”称号而又想往上靠的那些语言,
而不够资格据我所知都是因为不支持继承,可以说是否支持
继承是“面向对象”和“基于对象”之间的分水岭.
继承如此重要,自从他和“面向对象”一起出世后就很
受重用.可一直有一股暗流在地下涌动,最近甚至跳到了明处.
他们公开指责继承和耦合之间关系密切,并通过诬蔑耦合为
万恶之源的办法来达到诽谤继承的目的,并且公开叫嚣要少
用继承甚至不用继承.
事情是否真的象他们说的那样吗?难道模块独立性真的
那样的珍贵,低的耦合度真的那样的美好,竟值得用放弃继承
和使用“基于对象”语言为代价吗?
先谈耦合,一般来说,耦合不是什么好东西,耦合度越低
越好.但这并不是绝对的.
首先,不耦合和低耦合在很多情况下不太可能被实现.
不耦合是从理论上就是根本不可能的,只有 数据耦合 在实际
上也是不可能的,不然怎么会有什么类,还不是因为不管怎
么搞,函数们仍然一伙一伙的通过数据结构紧紧的耦合在一
起.至于类之间比较深的耦合也不只是继承,比如:Iterator.
不使用深耦合很多问题不可能解决.
而且,耦合最深的不是函数之间,更不是类之间,而是函
数内部,这个耦合问题是永远也不可能解决的.
其次,低耦合并不很重要.耦合度的重要性要小于内聚度,
在不能同时保证时,应先保证高内聚而不是低耦合.
再次,低耦合也未必有多大好处.低耦合往往造成模块的
数量成倍的增加或是出现一些过于巨大的模块.模块过多,使
用者了解单个模块简单了,但要了解更多的模块,可能把好处
抵消得差不多了.模块过大则更可怕了,以为过大的模块接口
可能是低耦合的,可内部肯定耦合的一塌糊涂.
再次,高耦合也常常有好处.在不少情况下,高耦合度的模
块要比低耦合度模块效率高.有时,做一个高耦合度模块是替代
复制和粘贴的最好办法.
最后,高耦合带来的害处是可以化解的.化解的办法有两个:
熟悉和标准化.
熟悉的作用,举个简单的例子,DOS,UNIX,Windows的系统
调用,那个不是涉及到系统内部的数据结构和实现细节,这可
不是一般的耦合了.可在这些系统上工作的程序员们不都活
得好好的吗?其实熟悉了也就不太用在乎高耦合了.
标准化,作用就更大了.我们可以为模块订出标准,耦合
度达到什么程度,什么细节需要暴露,什么细节必须隐藏,我
们都订成标准,一个版本一个版本的支持下去.上个例子中的
操作系统不都是这么干的吗?
另外,熟悉的人多的东西容易成为标准,成为标准的东西
容易被人熟悉.
现在谈继承和耦合之间的关系.主要是比较继承-耦合关
系和聚合-耦合关系.可能有不少人反复的告诉你们继承和耦
合关系十分密切,而聚合和耦合之间则关系疏远.真有这么回
事吗?
1.其实你现在看到的高耦合的继承和低耦合的聚合是一
种错觉,因为继承和聚合都出现在一个系统里,自然把高耦合
的部分做成继承,低耦合的部分做成耦合.如果你全用继承,
你将得到高耦合的继承和低耦合的继承;如果你全用聚合,你
将得到高耦合的聚合和低耦合的聚合.尤其可怕的是高耦合的
聚合,因为你不得不把某些类的细节完全公开,结果你会发现
聚合破坏起封装性来比倍受攻击的继承拿手多了.
2.聚合和相识关系有时也需要高耦合,例子就是Iterator.
3.可以建立独立于类实现的继承接口来降低继承的耦合
度,就象JAVA中的Interface独立于类实现一样.
综上所述,耦合并不象某些人所说的那样可怕,继承也
并不一定会带来比别的方式更高的耦合度.
关于继承和耦合这次就先说到这里,下次再说.
梁海鹰 2001年8月7日于北京
大家都听说过,有个称号叫“基于对象”,用来授予那些
没有资格获得“面向对象”称号而又想往上靠的那些语言,
而不够资格据我所知都是因为不支持继承,可以说是否支持
继承是“面向对象”和“基于对象”之间的分水岭.
继承如此重要,自从他和“面向对象”一起出世后就很
受重用.可一直有一股暗流在地下涌动,最近甚至跳到了明处.
他们公开指责继承和耦合之间关系密切,并通过诬蔑耦合为
万恶之源的办法来达到诽谤继承的目的,并且公开叫嚣要少
用继承甚至不用继承.
事情是否真的象他们说的那样吗?难道模块独立性真的
那样的珍贵,低的耦合度真的那样的美好,竟值得用放弃继承
和使用“基于对象”语言为代价吗?
先谈耦合,一般来说,耦合不是什么好东西,耦合度越低
越好.但这并不是绝对的.
首先,不耦合和低耦合在很多情况下不太可能被实现.
不耦合是从理论上就是根本不可能的,只有 数据耦合 在实际
上也是不可能的,不然怎么会有什么类,还不是因为不管怎
么搞,函数们仍然一伙一伙的通过数据结构紧紧的耦合在一
起.至于类之间比较深的耦合也不只是继承,比如:Iterator.
不使用深耦合很多问题不可能解决.
而且,耦合最深的不是函数之间,更不是类之间,而是函
数内部,这个耦合问题是永远也不可能解决的.
其次,低耦合并不很重要.耦合度的重要性要小于内聚度,
在不能同时保证时,应先保证高内聚而不是低耦合.
再次,低耦合也未必有多大好处.低耦合往往造成模块的
数量成倍的增加或是出现一些过于巨大的模块.模块过多,使
用者了解单个模块简单了,但要了解更多的模块,可能把好处
抵消得差不多了.模块过大则更可怕了,以为过大的模块接口
可能是低耦合的,可内部肯定耦合的一塌糊涂.
再次,高耦合也常常有好处.在不少情况下,高耦合度的模
块要比低耦合度模块效率高.有时,做一个高耦合度模块是替代
复制和粘贴的最好办法.
最后,高耦合带来的害处是可以化解的.化解的办法有两个:
熟悉和标准化.
熟悉的作用,举个简单的例子,DOS,UNIX,Windows的系统
调用,那个不是涉及到系统内部的数据结构和实现细节,这可
不是一般的耦合了.可在这些系统上工作的程序员们不都活
得好好的吗?其实熟悉了也就不太用在乎高耦合了.
标准化,作用就更大了.我们可以为模块订出标准,耦合
度达到什么程度,什么细节需要暴露,什么细节必须隐藏,我
们都订成标准,一个版本一个版本的支持下去.上个例子中的
操作系统不都是这么干的吗?
另外,熟悉的人多的东西容易成为标准,成为标准的东西
容易被人熟悉.
现在谈继承和耦合之间的关系.主要是比较继承-耦合关
系和聚合-耦合关系.可能有不少人反复的告诉你们继承和耦
合关系十分密切,而聚合和耦合之间则关系疏远.真有这么回
事吗?
1.其实你现在看到的高耦合的继承和低耦合的聚合是一
种错觉,因为继承和聚合都出现在一个系统里,自然把高耦合
的部分做成继承,低耦合的部分做成耦合.如果你全用继承,
你将得到高耦合的继承和低耦合的继承;如果你全用聚合,你
将得到高耦合的聚合和低耦合的聚合.尤其可怕的是高耦合的
聚合,因为你不得不把某些类的细节完全公开,结果你会发现
聚合破坏起封装性来比倍受攻击的继承拿手多了.
2.聚合和相识关系有时也需要高耦合,例子就是Iterator.
3.可以建立独立于类实现的继承接口来降低继承的耦合
度,就象JAVA中的Interface独立于类实现一样.
综上所述,耦合并不象某些人所说的那样可怕,继承也
并不一定会带来比别的方式更高的耦合度.
关于继承和耦合这次就先说到这里,下次再说.
梁海鹰 2001年8月7日于北京