内聚力和耦合力的区别


486

内聚和耦合之间有什么区别?

耦合和凝聚力如何导致软件设计的好坏?

有哪些示例概述了两者之间的差异以及它们对整体代码质量的影响?



3
我想指出这篇文章:SOLID软件开发,一次一步。格里斯,克里斯。
克里斯·范德·玛斯特

4
是该主题的最新文章
janisz

Answers:


702

内聚性是指类(或模块)可以做什么。缺乏凝聚力意味着班级会采取各种各样的行动-范围很广,没有专注于应该做什么。高凝聚力意味着班级专注于应该做的事情,即只涉及班级意图的方法。

低内聚力示例:

-------------------
| Staff           |
-------------------
| checkEmail()    |
| sendEmail()     |
| emailValidate() |
| PrintLetter()   |
-------------------

高内聚力示例:

----------------------------
| Staff                   |
----------------------------
| -salary                 |
| -emailAddr              |
----------------------------
| setSalary(newSalary)    |
| getSalary()             |
| setEmailAddr(newEmail)  |
| getEmailAddr()          |
----------------------------

至于耦合,它是指两个类/模块彼此之间如何相关或相依。对于低耦合类,更改一个类中的主要内容不应影响另一类。高耦合将使更改和维护代码变得困难;由于类紧密结合在一起,因此进行更改可能需要对整个系统进行改造。

好的软件设计具有高凝聚力低耦合性


12
我看不到如何删除一些方法,而添加其他方法会增加凝聚力。有人可以帮忙吗?
Saket Jain

3
@SaketJain不仅是删除一些方法并添加了其他方法。这就是方法与类目的的关系(如果该解释更清楚的话)。
莫里斯

4
顶部的低内聚力的例子看起来不错,我想您不小心要说“高内聚力”
relipse

37
@SaketJain Staff类不是我们检查,发送或验证电子邮件的地方。这些功能应该放在假设的Email类中,这就是内聚性低的原因。在第二个示例中,Staff类仅包含用于设置和获取与Staff相关的数据的正确信息。他们不会执行其他班级应该管理的动作。
Antonio Pantano

3
@JonathanC例子并不需要证明差异(就像在数学证明中一样)仍然是例子。随意回答或评论您觉得更有帮助的任何示例。在setget功能说明功能,更具体的“工作人员”语境-高特异性给予该例如其较高的凝聚力。
cellepo

81

内聚性是模块关系的指示。

耦合是模块之间关系的指示。

在此处输入图片说明

凝聚

  • 内聚性是模块内关系的指示。
  • 内聚力显示模块的相对功能强度。
  • 内聚性是组件/模块专注于单个事物的程度(质量)。
  • 在设计时,您应该争取较高的内聚性,即内聚的组件/模块专注于单个任务(即,一心一意),而与系统的其他模块的交互很少。
  • 内聚是数据隐藏的一种自然扩展,例如,类使所有成员可见,而该类具有默认可见性的包。内聚性是模块内部的概念。

耦合

  • 耦合是模块之间关系的指示。
  • 耦合显示了模块之间的相对依赖性/相互依赖性。
  • 耦合是组件/模块连接到其他模块的程度。
  • 在设计时,您应努力降低耦合度,即模块之间的依赖性应较小
  • 设置私有字段,私有方法和非公共类提供了松散的耦合。
  • 耦合是模块间的概念。

检查链接


77

在OO编程语言中模块内的高凝聚力和模块之间的低耦合通常被认为与高质量有关。

例如,每个Java类中的代码必须具有较高的内部凝聚力,但应尽可能松散地耦合到其他Java类中的代码。

Meyer的面向对象软件构造(第2版)的第3章很好地描述了这些问题。


3
这些概念并不仅限于OO编程。如果有的话,我建议OO语言的目标是引导程序员迈向高内聚/低耦合的目标。
哈奇

57

内聚性表明软件元素的职责之间如何相关和集中。

耦合是指软件元素与其他元素的连接强度。

该软件元素可以是类,包,组件,子系统或系统。并且在设计系统时,建议使用具有高内聚力并支持低耦合的软件元素。

低内聚性导致难以维护,理解和减少重用的整体类。同样,高耦合导致紧密耦合的类,并且更改往往不是局部的,难以更改的,并减少了重用。

我们可以假设一个场景,在该场景中,我们设计ConnectionPool具有以下要求的典型可监控显示器。请注意,对于像这样的简单类来说可能看起来太多了,ConnectionPool但是基本目的只是通过一些简单的示例展示低耦合高内聚性,我认为应该有所帮助。

  1. 支持建立连接
  2. 释放连接
  3. 获取有关连接与使用次数的统计信息
  4. 获取有关连接与时间的统计信息
  5. 将连接检索和释放信息存储到数据库中,以便以后报告。

低内聚性的情况下,我们可以ConnectionPool通过将所有这些功能/职责强制填充到单个类中来设计一个类,如下所示。我们可以看到,该类负责连接管理,与数据库交互以及维护连接统计信息。

低内聚连接池

凭借高度的凝聚力,我们可以在各个类中分配这些责任,并使之更加可维护和可重用。

高内聚连接池

为了演示低耦合,我们将继续ConnectionPool上面的高内聚图。如果我们看上图,尽管它支持很高的内聚性,但它ConnectionPoolConnectionStatistics类紧密耦合,并且PersistentStore直接与它们交互。相反,为了减少耦合,我们可以引入一个ConnectionListener接口,让这两个类实现该接口并让它们在ConnectionPool类中注册。然后,ConnectionPoolwill将遍历这些侦听器,并通知他们连接获取和释放事件,并减少耦合。

低耦合连接池

注意/文字或注意事项:对于这种简单的情况,可能看起来有些过头,但是如果我们想象一个实时情况,其中我们的应用程序需要与多个第三方服务进行交互以完成交易:将代码直接与第三方服务耦合意味着第三方服务的任何更改都可能导致我们在多个地方的代码发生更改,相反,我们可以让Facade这些代码在内部与这些多个服务进行交互,并且对服务的任何更改都将成为本地的,Facade并与第三方进行低耦合服务。


3
很好的答案!如果可能,您可以使用其他示例吗?连接池可能并非所有人都清楚。无论如何,它确实帮助了我。那谢谢啦!
Saket Jain

使用ConnectionListener接口如何有助于减少耦合?能否提供一个更易于理解的示例。
abhishek gupta

1
@abhishekgupta在此示例中,您可能已经注意到我们使用观察者模式来实现低/松耦合。进行此操作将有助于Observer如何创建松耦合设计?
Madhusudana Reddy Sunnapu

33

内聚性的提高和耦合的减少确实导致了良好的软件设计。

内聚力对您的功能进行分区,以使其简洁明了且最接近与之相关的数据,而去耦则确保功能实现与系统的其余部分隔离。

通过解耦,您可以更改实现,而不会影响软件的其他部分。

内聚性确保实现更特定于功能,同时更易于维护。

通过界面设计是减少耦合和增加内聚力的最有效方法。

那就是主要功能对象应该只通过它们实现的接口相互“了解”。接口的实现自然会引入内聚性。

尽管在某些情况下不现实,但应该将其作为设计目标。

示例(非常粗略):

public interface IStackoverFlowQuestion
      void SetAnswered(IUserProfile user);
      void VoteUp(IUserProfile user);
      void VoteDown(IUserProfile user);
}

public class NormalQuestion implements IStackoverflowQuestion {
      protected Integer vote_ = new Integer(0);
      protected IUserProfile user_ = null;
      protected IUserProfile answered_ = null;

      public void VoteUp(IUserProfile user) {
           vote_++;
           // code to ... add to user profile
      }

      public void VoteDown(IUserProfile user) {
          decrement and update profile
      }

      public SetAnswered(IUserProfile answer) {
           answered_ = answer
           // update u
      }
}

public class CommunityWikiQuestion implements IStackoverflowQuestion {
     public void VoteUp(IUserProfile user) { // do not update profile }
     public void VoteDown(IUserProfile user) { // do not update profile }
     public void SetAnswered(IUserProfile user) { // do not update profile }
}

在代码库中的其他位置,您可能有一个模块可以处理问题,无论它们是什么:

public class OtherModuleProcessor {
    public void Process(List<IStackoverflowQuestion> questions) {
       ... process each question.
    }
}

28

凝聚力的最佳解释来自鲍伯叔叔的《清洁法》:

类应具有少量实例变量。类的每个方法都应操纵这些变量中的一个或多个。通常,方法操纵的变量越多,该方法对其类别的凝聚力就越大。每个方法使用每个变量的类具有最大的内聚性。

通常,创建此类最大内聚的类既不建议也不可行。另一方面,我们希望凝聚力很高。当内聚性很高时,这意味着该类的方法和变量是相互依赖的,并且作为逻辑整体挂在一起。

保持函数较小和保持参数列表简短的策略有时会导致方法子集使用的实例变量激增。发生这种情况时,几乎总是意味着至少还有另一个班级试图脱离更大的班级。您应该尝试将变量和方法分为两个或多个类,以使新类具有更高的凝聚力。


我同意这可能是最好的解释,这是我在鲍伯叔叔中所喜欢的,他可以用几句话来解释实际含义。了解了这个定义,您可以立即看到应该对给定类进行哪些操作以增加其凝聚力。
Pawel Dubiel

13

简单来说,内聚表示代码库的一部分形成逻辑上单个原子单元的程度。另一方面,耦合表示单个单元彼此独立的程度。换句话说,它是两个或多个单元之间的连接数。数量越少,耦合越低。

本质上,高凝聚力意味着将彼此相关的代码库部分放在一个地方。同时,低耦合意味着尽可能地分离代码库的无关部分。

从内聚和耦合的角度来看,代码类型:

理想的是遵循准则的代码。它是松散耦合的,并且具有高度的凝聚力。我们可以用下面的图片说明这样的代码:在此处输入图片说明

God Object是引入高凝聚力和高耦合的结果。它是一种反模式,基本上代表单个代码,可一次完成所有工作: 当选择不同类或模块之间的边界时,选择不当就会发生。在此处输入图片说明 在此处输入图片说明

破坏性的去耦是最有趣的一种。有时,当程序员试图使代码库脱钩而使代码完全失去其焦点时,有时会发生这种情况:在此处输入图片说明

在这里阅读更多


1
优秀的文章和插图!如果我只想提出一个改进的建议,我喜欢“选择不当”如何将具有不相关语义的组件组保留在很小的一群中,但是我认为它们之间应该有明显更多的箭头。毕竟,即使在您的4平方图中,这也是落入“耦合”轴上限的那个。
Slawomir Brzezinski

1
我还要说,“选择不当”在每个群内应该有更少的箭头。使用您文章中的“文件夹结构”示例,您将其归类为“选择不佳”的存储库或工厂,肯定不会互相交谈。
Slawomir Brzezinski

更新:我向图像的原始作者提出了这些建议,并且作者同意了这些建议
Slawomir Brzezinski

11

软件工程中的内聚性是某个模块的元素所属的程度。因此,它衡量了由软件模块的源代码表达的每个功能之间的关联程度。

简单来说,耦合就是一个组件(尽管不是必须的,再想一想一个类)对另一组件的内部运作或内部元素了解多少,即它对另一组件具有多少知识。

我写了一篇有关此的博客文章,如果您想阅读更多有关示例和图纸的详细信息。我认为它回答了您的大多数问题。


4

在此处输入图片说明

凝聚力指的是单个类的设计方式。内聚性是与确保类以单一且重点突出的目的进行设计紧密相关的面向对象原则。一个班级越集中,该班级的凝聚力就越大。高内聚性的优点是,此类类比低内聚性类更易于维护(且更改频率较低)。高凝聚力的另一个好处是,具有重点突出目的的类比其他类更易于重用。

在上图中,我们可以看到,在低内聚性中,只有一个类负责执行很多不常见的工作,从而减少了重用和维护的机会。但是,由于具有很高的凝聚力,因此所有作业都有一个单独的类来执行特定作业,从而提高了可用性和维护性。


2

内聚力(Co-hesion):Co表示在一起hesion表示粘附。将不同物质的颗粒粘合在一起的系统。

对于实际示例:img礼貌
在此处输入图片说明

整体大于部分之和-亚里斯多德。

  • 凝聚是一个序类型的测量和通常被描述为“高内聚”或“低凝聚力”。具有高内聚力的模块往往是可取的,因为高内聚力与软件的几个理想特征相关,包括鲁棒性,可靠性,可重用性和可理解性。相反,低内聚性与不良特征相关,例如难以维护,测试,重用甚至理解。维基

  • 耦合通常与凝聚力形成对比。低耦合通常与高凝聚力相关,反之亦然。低耦合通常是计算机系统结构良好和设计良好的标志,并且与高内聚性结合使用时,可以达到较高的可读性和可维护性的总体目标。维基


1

我认为可以将差异如下:

  • 内聚表示代码库的一部分形成逻辑上单个原子单元的程度。
  • 耦合表示单个单元彼此独立的程度。
  • 在不破坏内聚力的情况下归档完全去耦是不可能的,反之亦然。

在这篇博客文章中,我将详细介绍它。


1

内聚力是模块相对功能强度的指标。

  • 内聚模块执行单个任务,几乎不需要与程序其他部分中的其他组件进行交互。简而言之,一个内聚模块应该(理想地)只做一件事。
  • 常规视图:

    模块的“一心一意”

  • OO视图:

    内聚意味着组件或类仅封装彼此之间以及与类或组件本身密切相关的属性和操作

  • 凝聚力水平

    功能

    层

    通讯

    顺序

    程序

    时间

    效用

耦合表示模块之间的相对相互依赖性。

  • 耦合取决于模块之间的接口复杂性,对模块进行输入或引用的时间点以及通过接口传递的数据。

  • 传统视图:组件与其他组件以及与外部世界的连接程度

  • 面向对象视图:对类之间相互连接程度的定性度量

  • 耦合程度

    内容

    普通

    控制

    邮票

    数据

    常规通话

    类型使用

    包含或导入

    外部编号


1

耦合 =两个模块之间的交互/关系... 内聚 =一个模块中两个元素之间的交互。

一个软件由许多模块组成。模块由元素组成。考虑模块是程序。程序中的功能是一个元素。

在运行时,程序的输出将用作另一个程序的输入。这称为模块间交互或过程间通信。这也称为耦合。

在单个程序中,一个函数的输出将传递给另一个函数。这称为模块内元素的交互。这也称为内聚力。

例:

耦合 = 2个不同家庭之间的交流... 内聚 =一个家庭中父子之间的交流。


1
那么,如何从它们对软件的影响的角度来解释它们呢?
Itban Saeed

一个软件由许多模块组成。模块由元素组成。考虑模块是程序。程序中的功能是一个元素。
Dipankar Nalui

1

简而言之,凝聚力意味着一个类应该代表一个概念。

如果所有类功能都与该类所代表的概念相关,则该类的公共接口是内聚的。例如,不是具有CashRegister类,而是具有CashRegister和Coin功能的凝聚力使其分为2类-CashRegister和Coin类。

耦合中,一个类依赖于另一个,因为它使用该类的对象。

高耦合的问题在于它会产生副作用。一个类中的一个更改可能导致另一类中的意外错误,并可能破坏整个代码。

通常,高内聚和低耦合被认为是高质量的OOP。


0

术语凝聚力的确是有点反直觉的东西它是指在软件设计。

内聚力的共同含义是,可以很好地粘合在一起的东西是统一的,其特征是像分子吸引力那样的牢固结合。但是,在软件设计中,这意味着争取一个只做一件事的类,因此甚至不涉及多个子模块。

也许我们可以这样想。当零件是唯一零件时,它具有最大的凝聚力(仅做一件事,无法进一步分解)。这是软件设计中所需要的。凝聚力只是“单一责任”或“关注分离”的别称。

手上的耦合这个术语非常直观,这意味着当一个模块不依赖太多其他模块并且与其连接的模块可以很容易地替换时,例如遵循liskov替换原理


人们为什么继续使用单词模块而不是课堂?
北方人

1
@northerner只是更通用的术语。
zar

0

理论差异

凝聚

  • 内聚力是模块相对功能强度的指标。
  • 内聚模块执行单个任务,几乎不需要与程序其他部分中的其他组件进行交互。
  • 具有高内聚力和低耦合的模块被认为在功能上独立于其他模块。

内聚力分类

1.巧合2.逻辑3.时间4.程序5.沟通6.顺序7.功能

耦合

  • 耦合表示模块之间的相对相互依赖性。
  • 两个模块之间的耦合程度取决于它们的接口复杂性。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.