什么是高凝聚力,以及如何使用它/使之成为可能?
我正在学习计算机编程,在几个地方我偶然发现了凝聚力的概念,我明白软件具有“高凝聚力”是可取的,但是这意味着什么? 我是C ++入门的一名Java,C和Python程序员,学习C ++,在C ++ Primer中没有提到它的索引,你可以指点一些关于这个主题的链接吗? 我没有find关于计算机科学内聚信息的维基百科页面,因为它只是说它是一个定性的测量,并没有给出真正的代码示例。
高度凝聚力是当你有一个明确的工作类。 当一个class级做了很多没有太多共同点的工作时,低凝聚力就是。
我们来看一下这个例子:
你有一个增加两个数字的类,但是同一个类创build一个显示结果的窗口。 这是一个低凝聚力的类,因为窗口和添加操作没有太多共同之处。 窗口是程序的可视化部分,添加function是它背后的逻辑。
要创build一个高度一致的解决scheme,你将不得不创build一个类窗口和类和。 窗口将调用Sum的方法来获得结果并显示它。 这样你将分开开发应用程序的逻辑和GUI。
史蒂夫·麦康奈尔的代码完整性的解释 :
凝聚力指一个class级中的所有例程或例程中的所有代码如何支持一个中心目的 。 包含强相关function的类被描述为具有强大的内聚性,启发式目标是尽可能强化内聚力。 凝聚力是pipe理复杂性的一个有用的工具,因为一个类中的代码越多,支持一个中心的目的,你的大脑就越容易记住代码所做的一切。
从Bob叔叔的Clean Code中实现它的一些方法:
类应该有less量的实例variables 。 每个类的方法都应该处理一个或多个这些variables。 一般来说,一个方法操作的variables越多,该方法对其类的内聚性越强 。 每个方法使用每个variables的类是最大程度上内聚的。
一般来说,build立这种最大程度的凝聚力的课程既不可取也不可能; 另一方面,凝聚力高。 当凝聚力高时,就意味着这个阶级的方法和variables是相互依存的,并且是一个逻辑整体。
凝聚力的概念与耦合的概念密切相关; 还有一个基于高度凝聚力的启发式原则,即单一责任原则(来自SOLID的S)。
高凝聚力是软件工程的概念。 基本上说,一个class级只应该做它应该做的事情,并且完全做到这一点。 不要用它不应该做的function来重载它,而且与它直接相关的东西也不应该出现在其他类的代码中。
例子是相当主观的,因为我们也必须考虑规模。 一个简单的程序不应该太模块化,否则会被分割; 而一个复杂的程序可能需要更多的抽象层次来照顾复杂性。
如电子邮件类。 它应该包含来自cc,bcc,subject,body的数据成员,并且可能包含这些方法saveAsDraft(),send(),discardDraft()。 但是login()不应该在这里,因为有很多电子邮件协议,应该单独实现。
凝聚力通常使用LCOM(缺乏凝聚力)度量标准来衡量,最初的LCOM度量来自Chidamber和Kemerer。 请参阅: http : //www.computing.dcu.ie/~renaat/ca421/LCOM.html
一个更具体的例子:如果一个class级有一个私人领域和三个方法; 当所有三种方法都使用这个字段来执行一个操作时,这个类是非常内聚的。
有凝聚力的类的伪代码:
class FooBar { private SomeObject _bla = new SomeObject(); public void FirstMethod() { _bla.FirstCall(); } public void SecondMethod() { _bla.SecondCall(); } public void ThirdMethod() { _bla.ThirdCall(); } }
如果一个class级有三个私人领域和三个方法, 当所有三种方法只使用三个领域中的一个时,那么这个class级的凝聚力就差了。
一个不太有凝聚力的阶级的伪代码:
class FooBar { private SomeObject _bla = new SomeObject(); private SomeObject _foo = new SomeObject(); private SomeObject _bar = new SomeObject(); public void FirstMethod() { _bla.Call(); } public void SecondMethod() { _foo.Call(); } public void ThirdMethod() { _bar.Call(); } }
class级做一件事的原则是来自罗伯特·C·马丁的单一责任原则 ,是固体原则之一。 原则规定,一个阶级应该只有一个理由要改变。
保持接近单一责任原则可能会导致更多的内聚代码,但在我看来,这是两码事。
这是一个低凝聚力的例子:
class Calculator { public static void main(String args[]) { //calculating sum here result = a + b; //calculating difference here result = a - b; //same for multiplication and division } }
但高凝聚力意味着类中的function做他们应该做的事(就像他们被命名)。 而不是一些function做一些其他function的工作。 所以,下面是一个高度凝聚力的例子:
class Calculator { public static void main(String args[]) { Calculator myObj = new Calculator(); System.out.println(myObj.SumOfTwoNumbers(5,7)); } public int SumOfTwoNumbers(int a, int b) { return (a+b); } //similarly for other operations }
凝聚力意味着一个类或一个方法只做一个定义的工作。 方法或类的名称也应该是不言自明的。 例如,如果你写一个计算器,你应该命名类“计算器”而不是“asdfghj”。 你也应该考虑为每个任务创build一个方法,例如减去()add()等…将来可能使用你的程序的程序员确切地知道你的方法正在做什么。 好的命名可以减less评论的努力
也是一个原则干 – 不要重复自己
考虑凝聚原则的一般方法是,你应该find一个代码以及依赖于它或者依赖于它的其他代码。 凝聚力可以而且应该应用于class级以上的成分水平。 例如,一个包或名称空间理想情况下应该包含与某些常见主题相关的类,这些类与依赖于其他包/名称空间的依赖程度相关性更大。 即保持本地依赖关系。
在这种情况下, MSDN的文章可能比维基百科更具信息性。
术语凝聚力最初用来描述源代码模块,作为模块源代码相互关联程度的定性度量。 凝聚力的想法被用于各种领域。 比如说一个部队,比如一个军事单位,可能是有凝聚力的,这就意味着单位里的人们为了一个共同的目标而共同努力。
源代码内聚的本质是,一个模块中的源代码共同朝着共同的,明确的目标前进。 创build模块输出所需的最less量的源代码是在模块中,而不是更多。 接口定义良好,input通过接口stream入,输出通过接口回stream。 没有副作用,重点是极简主义。
function强大的模块的好处是开发和自动化unit testing非常简单。 事实上,模块的内聚性的一个好方法就是为模块创build一整套详尽的unit testing。
模块可以是面向对象的语言中的类,也可以是function语言中的函数,也可以是诸如C的非面向对象的语言。在测量内聚的这个领域中的大部分原始工作主要涉及与IBM的COBOL程序一起工作20世纪70年代,凝聚力绝对不只是一个面向对象的概念。
从凝聚力的概念和相关的耦合概念出发,研究的初衷是研究易于理解,维护和扩展的程序的特征。 目标是能够学习编程的最佳实践,编写这些最佳实践,然后将这些实践传授给其他程序员。
好的程序员的目标是编写源代码,在环境和问题得到解决的情况下,它的内聚力是尽可能高的。 这意味着在一个大的应用程序中,源代码体的一些部分将与其他部分有所不同,以及该模块或类中源代码的内聚程度。 有些时候,你可以得到的最好的是由于你试图解决的问题而产生的暂时的或者连续的凝聚力。
最好的凝聚力是function的凝聚力。 具有function性内聚力的模块类似于math函数,因为您提供了一组input并获得特定的输出。 一个真正的function模块不会产生副作用,也不会维持任何状态。 它将有一个定义良好的接口来封装模块的function,而不暴露模块的任何内部,而使用该模块的人将提供一组特定的input并获得特定的输出作为回报。 一个真正的function模块也应该是线程安全的。
许多编程语言库包含许多function模块的例子,无论是类,模板还是function。 最具function的凝聚力的例子是math函数,如罪,余弦,平方根等。
其他function可能有副作用或维持某种状态,导致使这些function的使用更复杂。
例如,一个引发exception或设置全局错误variables(在C中为errno
)或必须在序列中使用的函数( strtok()
函数是来自标准C库的一个示例,因为它保持内部状态),或者提供必须被pipe理的指针或者向日志实用程序发出日志的指针都是不再具有function的内聚函数的例子。
我已经阅读了Yourdon和Constantine的原着“结构化程序devise”(Structured Programming),在这本书中,我在20世纪80年代首次发现了凝聚力的概念,并且Meilir Page-Jones的书“结构化系统devise实用指南”耦合和凝聚力。 Yourdon和Constantine的书似乎更有学术性。 史蒂夫·麦康奈尔(Steve McConnell)的“代码完整版”(Code Complete)是相当不错的,实用的,修订版有很多好的编程实践。