越来越感觉到,弱耦合性是系统可维护性的关键, 有必要研究一下各种耦合的形态及相应解耦手段。
Robert C. Martin 在他的《敏捷软件开发》里提出了很多面向对象的原则,《代码大全》里也有一些,本质上都是为了实现弱耦合。
对耦合这个概念本身贡献最大的人可能是Meilir Page-Jones,他在他的《UML面向对象设计基础》中使用了connascence这个词(单词里的第一个a发/ei/音)。 Connascence就是Coupling的同义词,Page-Jones给出了它的定义,还指出了它有几种类别。
另有一个叫
Jim Weirich的Ruby高手对connascence非常感兴趣。他把它称为OO理论中的Grand Unified Theory(物理学术语). 他在一次演讲中专门介绍了这个东西,并有一定的展开。
我本想找一本专门讲弱耦合的书,但可惜目前没有; 于是只好自己研究一下上面提到的材料,下面是一些笔记。
附资源:
connascence的wiki页面: http://en.wikipedia.org/wiki/Connascent_software_components
Meilir Page-Jones的书:Fundamentals of Object-Oriented Design in UML, 看第三部分就好
Jim Weirich的演讲:http://confreaks.net/videos/77-mwrc2009-the-building-blocks-of-modularity
====================================================================
Connascence的定义:两个软件元素A和B之间,如果A改变,B也就必须改变, 或者当某第三方元素发生改变时,A和B必须同时改变。
———————————————————-
各种Connascence:
静态Connascence:
1. connascence of name
methodA()改名为methodB()时, 调用methodA()的地方都要改名
2. connascense of type or class
如果变量从值100变成了一个很大的数, 则变量类型可能要从int改成BigInteger
3.connascense of convention
magic number就是一个典型的例子
4.connascence of algorithm
比如:某个方法以Collection作为返回值签名,其实现时用的是List; 而使用这个方法的人知道了这个秘密,于是拿到返回的Collection后立即cast为List来使用。如果该方法改用Set返回Collection,那调用代码的地方就都要改。
5.connascence of position
a.两条代码必须以正确的顺序出现,不能颠倒,比如方法签名中两个参数之间的顺序
b.或者两条代码之间必须相邻,中间不能间断
动态Connascence:
1.connascence of execution
connascence of position 在执行期间的体现,比如变量使用前必须先声明
2.connascence of timing
如: A操作必须在3秒内完成,然后B操作执行时才不会出错.
3.connascence of value
如:三角形三个角之和必须为180度
4.connascence of identity
比如Message Queue环境下,消费者和提供者指向的queue必须是同一个queue
contranascence (差异共生性)
A和B必须有所不同。比如两个变量分别叫i和j, 如果想把i改名为j,则j必须改成其它名字
———————————————————-
Connanscence的度量与解耦办法:
1. Strength/Degree: 一方改变导致另一方需改变的程度
2. Locality: 两个connanscent元素之间的远近程度
可以把Connascence of position退化成 connascence of name, 比如把超过五个以上的参数组装成一个参数对象。
可以把connascense of convention变成connascense of name, 比如用一个常量替代Magic Number
Locality好的connanscent元素之间可以允许较强的耦合,比如修改方法签名中的变量名再跟着修改方法体内的相应的名字并不难; Locality弱的元素之间则应该使用较弱的耦合,比如web service方法中的参数最好都用参数对象来组装,以避免Connascence of position问题。
======================
处理Connascence的三个原则:
1.将系统拆分为封装的元素,使得整体的connascence达到最小化
2.将任何跨越封装边界的connascence最小化
3.在封装边界范围内将connascence最大化
我觉得这一段对组件化设计很有启发意义,可惜作者没有进一步展开。