高聚合、低耦合

不知道是否是记忆力不如年少时好了,还是因为生活中事务繁杂了,常常会忘了以前查过的东西。

面向对象的目标就是设计出高聚合、低耦合的程序。聚合和耦合并非是一对相反的概念,但:只要做到了高聚合,那么自然而然就做到了低耦合。

聚合(Cohesion)是一个模块内部各成分之间相关联程度的度量。

这里有多个含义值得考虑。首先,聚合是对一个模块内部的度量,这也是许多情况下我们把聚合称之为内聚的原因。第二,这里出现的模块是广义的模块,它可能是子系统,可能是功能模块,也可能是功能模块中的某一个类。从不同的层次看,聚合的程度也会有所不同。至于为什么不同,后面会有解释。第三,模块的成分包括模块的行为和状态。要做到高聚合,那么模块内部的行为必须要与模块的内部状态紧密关联。通俗来讲,一个模块仅完成一个独立的功能,模块内部不存在与该功能无关的操作或状态。

举一个例子:

有两座城市A和B,连接两座城市的公路一天到晚总是拥堵不堪。经过“有关部门”调查之后发现,这两座城市中有两家公司a和 b,a的工厂建造在A,而该工厂的员工都居住在B,所以每天早上大批员工从B出发前往A,并在傍晚返回;类似的,a2公司的运输车在每天的工作时间都需要在制瓶工厂和灌装工厂穿梭来往。

很明显,如果a的工厂和员工居住地都在同一城市,而b的两座工厂都建造在另一座城市,那么城市之间的交通状况将会明显改善。

上面两座城市间之所以出现交通的问题,是因为每座城市的“聚合性”都比较低:不相关的两个公司出现在了同一座城市,使得城市内部交通的利用率比较低,而城市之间的交通出现了超负荷。

耦合(Couping)是模块之间相关联程度的度量。

相对于聚合的内向性,耦合关注的是某一模块和其他模块之间的关联性。其实从前面的例子里,我们已经不可避免的提到了耦合的问题:由于两座城市之间的相互联系过于紧密,导致了城市之间的交通拥堵。另外一个潜在的问题就是,如果其中一座城市内部的交通出现了问题,另一座城市也会受到影响。我们所追求的低耦合,就是将两个模块之间的关联尽可能的降低,一个模块发生变化对于其他模块的影响尽可能的小。

再讲一个例子:

相信大部分的80后小的时候都玩过一种掌上游戏机,这种游戏机内含一个俄罗斯方块的游戏。这种游戏机虽然风靡一时,但是不多久就渐渐淡出了市场,因为这种游戏机只有俄罗斯方块可以玩儿,当我们玩儿腻了的时候,这个游戏机也就如同废物一个了。

同期,任天堂推出一款后来风靡了将近20年的红白机,这种游戏机市场寿命如此之长并非游戏机本身质量有多好,而是因为基于红白机开发的游戏层出不穷,经典无数。魂斗罗、超级玛丽在当时哪怕是现在也是无人不知。红白机的游戏本身并不存储在游戏机当中,每当有新游戏推出的时候,只需要购买新的卡带即可。正是这种游戏机和卡带相对独立的设计,使得游戏的设计厂商无需关心游戏机的实现细节,只要遵循游戏机提供的接口(插槽)。很多游戏的设计厂商也从红白机庞大的市场中分得一杯羹。大多数的玩家可能不知道,魂斗罗并非任天堂推出的产品,而是目前以《实况足球》系列闻名世界的KONAMI公司于1988年从街机移植到红白机上的。

回到耦合的话题上来,因为早先的掌上游戏机将游戏本身内置在机器当中,游戏和机器这两个模块之间的关系过于紧密,所以游戏玩儿腻了,游戏机就没用了,游戏机出问题了,游戏也再也不能玩儿了。而红白机的游戏和游戏机之间的关系是相对独立的,只要它们都遵循制定好的协议,就可以独立的发展和变化。游戏卡带摔坏了,其他的游戏一样可以在机器上运行;自己的游戏机坏了,把卡带拿到朋友家的游戏机上也能玩儿。红白机发展到后期,连游戏机的手柄也是可插拔的,如果手柄坏了,也只需要更换手柄即可。

那么,我们如何看待聚合和耦合在实际当中的应用呢?我们的程序怎样才算是做到了高聚合和低耦合呢?

前面曾经提到,从不同的层次看,聚合和耦合的程度也会有所不同。A和B的例子当中,从城市的层次来看,第二种设计完全达到了高内聚和低耦合的目标,然而,如果从城市的不同区域来看,这样的设计内聚性还不够。如果我们一直追究下去,恐怕a所有的员工都要住在生产线上了。一味的追求高内聚,必然会造成模块的功能过于单一,而模块的数量出现急剧膨胀。所以,我们在设计和实现程序时必须要斟酌模块间的聚合和耦合程度,有兴趣的朋友也可以去研究聚合性指标与耦合性指标。

 

内容主要摘自网络

posted @ 2020-05-06 16:06  IceArrow  阅读(1325)  评论(0编辑  收藏  举报