我正在学习计算机编程,在几个地方我偶然发现了凝聚力的概念,我理解软件具有“高凝聚力”是理想的,但这意味着什么?我是一名Java,C和Python程序员,从C ++ Primer一书中学习C ++,它在索引中没有提到内聚,你能指点我关于这个主题的一些链接吗?我没有找到关于计算机科学凝聚力信息的维基百科页面,因为它只是说它是一个定性测量,并没有提供真实的代码示例。
答案 0 :(得分:216)
高凝聚力是指你有一个能完成明确工作的班级。低凝聚力是指一个班级做很多没有太多共同点的工作。
我们来看这个例子:
您有一个添加两个数字的类,但同一个类会创建一个显示结果的窗口。这是一个低内聚类,因为窗口和添加操作没有太多共同之处。窗口是程序的可视部分,添加功能是它背后的逻辑。
要创建高度内聚的解决方案,您必须创建一个类Window和一个类Sum。该窗口将调用Sum的方法来获取结果并显示它。这样,您将单独开发应用程序的逻辑和GUI。
答案 1 :(得分:38)
解释Steve McConnell的代码完成的内容:
凝聚力是指一个类或所有例程中所有例程的紧密程度 例程中的代码支持中心目的。包含的类 强烈相关的功能被描述为具有强大功能 凝聚力,启发式目标是使凝聚力如同强大 可能。 Cohesion是管理复杂性的有用工具,因为 一个类中的代码越多,支持中心目的就越容易 你的大脑可以记住代码所做的一切。
通过Bob叔叔的清洁代码实现它的一些方法:
类应具有少量实例变量。每一个 类的方法应该操纵这些变量中的一个或多个。 通常方法操作的变量越多,内聚性越强 该方法到它的类。每个变量使用的类 每种方法都具有最大的凝聚力。
一般来说,这既不可取 也不可能创造出这样最具凝聚力的课程;在另一 我们希望凝聚力很高。凝聚力很高的时候 意味着类的方法和变量是相互依赖的 作为一个逻辑整体挂在一起。
凝聚力的概念与耦合的概念密切相关;此外,还有一个基于高内聚启发式的原则,称为单一责任原则(SOLID中的S)。
答案 2 :(得分:17)
高凝聚力是一种软件工程概念。基本上,它说一个班级应该只做它应该做的事情,并完全做到。不要使用它不应该执行的函数来重载它,并且与它直接相关的任何内容都不应该出现在其他类的代码中。
示例非常主观,因为我们还必须考虑比例。一个简单的程序不应过于模块化,也不应该分散;虽然复杂的程序可能需要更多级别的抽象来处理复杂性。
e.g。电子邮件类。它应该包含数据成员to,from,cc,bcc,subject,body,并且可能包含这些方法saveAsDraft(),send(),discardDraft()。但是login()不应该在这里,因为有很多电子邮件协议,应该单独实现。
答案 3 :(得分:10)
凝聚力通常使用LCOM(缺乏凝聚力)指标之一来衡量,原始LCOM指标来自Chidamber和Kemerer。参见例如: http://www.computing.dcu.ie/~renaat/ca421/LCOM.html
一个更具体的例子: 如果一个类有一个私有字段和三个方法;当所有三种方法都使用此字段执行操作时,该类非常有凝聚力。
有凝聚力的类的伪代码:
class FooBar {
private SomeObject _bla = new SomeObject();
public void FirstMethod() {
_bla.FirstCall();
}
public void SecondMethod() {
_bla.SecondCall();
}
public void ThirdMethod() {
_bla.ThirdCall();
}
}
如果一个类有三个私有字段和三个方法;当所有三种方法只使用三个字段中的一个时,那么这个类就很难有凝聚力。
缺乏凝聚力的类的伪代码:
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();
}
}
班级做一件事原则是Single Responsibility Principle来自罗伯特C.马丁,是SOLID原则之一。该原则规定一个班级应该只有一个改变的理由。
接近单一责任原则可能会产生更具凝聚力的代码,但在我看来,这是两个不同的事情。
答案 4 :(得分:3)
这是低凝聚力的一个例子:
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
}
}
但高内聚意味着类中的函数执行它们应该执行的操作(就像它们被命名一样)。而不是某些功能完成其他功能的工作。因此,以下可以是高凝聚力的一个例子:
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
}
答案 5 :(得分:2)
考虑内聚原则的一般方法是,您应该找到一个代码以及依赖于它或依赖于它的其他代码。凝聚力可以而且应该应用于高于班级水平的成分水平。例如,一个包或命名空间理想情况下应该包含与某个共同主题相关的类,并且它们依赖于其他包/命名空间而言更依赖于相互依赖。即保持依赖本地。
答案 6 :(得分:1)
内聚意味着类或方法只执行一个已定义的作业。方法或类的名称也应该是不言自明的。例如,如果你写一个计算器,你应该命名为“计算器”,而不是“asdfghj”。你也应该考虑为每个任务创建一个方法,例如subtract()add()等... 可能在将来使用您的程序的程序员确切知道您的方法正在做什么。良好的命名可以减少评论工作
原则也是干 - 不要重复自己
答案 7 :(得分:1)
大多数答案都没有解释什么是内聚力,在鲍伯叔叔的书干净代码中有很好的定义。
类应具有少量实例变量。每一个 类的方法应操纵这些变量中的一个或多个。 通常,方法操纵的变量越多,则内聚性越强 该方法是其类。一个类,其中每个变量由 每种方法都具有最大的凝聚力。一般来说,这都不可取 不可能创建这种最大内聚的类;在另一 一方面,我们希望凝聚力很高。凝聚力高时 表示该类的方法和变量是相互依赖的, 在一起作为一个逻辑整体。
让我用类定义来解释
class FooBar {
private _bla;
private _foo;
private _bar;
function doStuff()
if(this._bla>10){
this._foo = 10;
this._bar = 20;
}
}
function doOtherStuff(){
if(this._foo==10){
this._bar = 100;
this._bla = 200;
}
}
}
如果您看到上面的示例,则类是内聚的,这意味着变量在类之间共享以一起工作。更多的变量被共享,这意味着该类是高度内聚的并且可以作为一个单元工作。
答案 8 :(得分:0)
MSDN's关于它的文章可能比维基百科更具信息量。
答案 9 :(得分:0)
术语凝聚力最初用于描述源代码模块,作为模块源代码相互关联程度的定性度量。凝聚力的概念用于各种领域。例如,军队等一群人可能具有凝聚力,这意味着该部门的人员共同努力实现共同目标。
源代码内聚的本质是模块中的源代码共同朝着一个共同的,明确定义的目标。创建模块输出所需的最少源代码量在模块中,不再存在。接口定义良好,输入通过接口流入,输出通过接口流出。没有副作用,重点是极简主义。
功能强大的模块的一个好处是开发和自动化单元测试很简单。事实上,模块内聚力的一个很好的衡量标准是为模块创建一整套详尽的单元测试是多么容易。
模块可以是面向对象语言中的类,也可以是函数式语言或非面向对象语言中的函数,例如C.在这个测量内聚的领域中的大部分原创工作主要涉及IBM的COBOL程序。早在20世纪70年代,凝聚力绝对不仅仅是一种面向对象的概念。
研究的初衷是凝聚力的概念和相关的耦合概念来自于对易于理解,维护和扩展的程序特征的研究。目标是能够学习编程的最佳实践,编写最佳实践,然后将这些实践教授给其他程序员。
优秀程序员的目标是编写源代码,在环境和问题得到解决的情况下,内核的内聚力尽可能高。这意味着在大型应用程序中,源代码体的某些部分将与该模块或类中的源代码的内聚级别的其他部分不同。有些时候,你可以得到的最好的是时间或连续的凝聚力,因为你试图解决的问题。
最佳的凝聚力是功能凝聚力。具有功能内聚的模块类似于数学函数,因为您提供一组输入并获得特定输出。真正的功能模块除了输出之外不会产生副作用,也不会保持任何类型的状态。它将具有良好定义的接口,其封装模块的功能而不暴露模块的任何内部,并且使用该模块的人将提供特定的输入集并获得特定的输出作为回报。一个真正实用的模块也应该是线程安全的。
许多编程语言库包含许多功能模块的示例,无论是类,模板还是函数。功能最强大的例子是数学函数,如sin,余弦,平方根等。
其他功能可能会产生副作用或维持某种状态,导致这些功能的使用更加复杂。
例如,抛出异常或在C中设置全局错误变量(errno
)或必须在序列中使用的函数(strtok()
函数是标准C库中的一个示例,因为它维护一个内部状态)或提供一个必须被管理的指针或向一些日志实用程序发出日志都是一个不再具有功能凝聚力的函数的例子。
我读过Yourdon和Constantine的原着结构编程,我在20世纪80年代第一次看到了凝聚力的想法和Meilir Page-Jones的“结构化系统设计实用指南”,而Page-Jones做得更好描述耦合和凝聚力的工作。 Yourdon和Constantine的书似乎更具学术性。史蒂夫麦康奈尔的书代码完全是非常好的和实用的,修订版有很多关于良好的编程实践的说法。