低耦合和高内聚不是相互依赖的吗?

Don't low coupling and high cohesion depend on each other?

我应该为同一代码编写两个版本。一个具有 low 耦合和 high 内聚,另一个仍然具有 low 耦合,但这次具有 凝聚力。我真的不明白有什么区别?怎么才能做到低耦合低内聚呢?它们看起来如此相关,以至于这是不可能做到的。

有人可以解释一下吗?也许举个例子? 谢谢!

例如,您有两个 classes,只有当两个 classes 都存在时才有效。 class 中功能的相似性称为内聚,事物如何归属在一起,但它们如何相互作用称为耦合。

因此,如果您编写的程序具有低耦合和高内聚性,则意味着该程序的 class 易于使用和重用,并且 class 的内部属于一体.所以 classes 充满了显示相似性的方法。

通过这种方式,可以很容易地更改程序的一部分,而不必在多个地方更改整个代码。因此,耦合通常是描述实现的难易程度的术语,内聚性用于衡量 class 中方法之间的相似性。因此,如果你想构建低耦合和低内聚的东西,你将不得不构建易于在程序中实现的东西,但会破坏封装。

耦合和内聚在某种程度上是两个接近的概念,但并不相同。你的设计应该有:

  1. 低耦合:这意味着你的classes不应该依赖于其他classes(尤其是具体的classes) 太多了。你必须尽可能地解耦它们。解耦有助于可重用性(面向对象软件工程的目标)。因为当您重复使用这样的 classes 时,您不需要将任何其他 class 与您的 class 一起使用来使其工作。 Facade 等许多设计模式都实现了这一目标。

  2. 高凝聚力:这意味着你的class不应该包括很多不相关的任务。当你增加凝聚力时,代码理解变得更容易,因为 class 正在做一些连贯的任务。这也增加了可重用性。一些设计模式如 Visitor 有这个目标。

在继续中,我举了 3 个 class 可能更有意义的例子:

#include <Document>
#include <Printer>
#include <SpellCheker>
class HighCoupling{
    // This class need other class to be usable
    Document *doc;
    Printer *activePrinter;
    CretaeDocument() { /*...*/ }
    SaveDocument() { /*...*/ }
    PrintDocument() { /*...*/ }    
    CheckSpell() { /*...*/ }    
};

#include <Document>
class LowCouplingHighCohesion {
    // This class don't need other classes
    // This class is a specialist on some task
    CretaeDocument() { /*...*/ }
    SaveDocument(Format *) { /*...*/ }
    LoadDocument() { /*...*/ }
};

#include <Document>
class LowCouplingLowCohesion {
    // This class don't need other classes
    // This class do many unrelated things
    CretaeDocument() { /*...*/ }
    SaveDocument() { /*...*/ }
    OpenDocument() { /*...*/ }
    Undo() { /*...*/ }
    ChangeDocumentBackground()  { /*...*/ }
    SearchInDocument() { /*...*/ }
};

意思不同

  1. 耦合 指的是具有负面意义 的事物。因此,根据 SOLID 规则,您必须尝试以 松散耦合 的方式构建您的应用程序。 例如,Gof patterns (e.g., Abstract Factory) and DI containers(例如 MS Unity 或 .NET 世界中的 NInject)可以帮助您实现这一点。 松散耦合代码意味着如果您需要将新的 class 插入到您的应用程序中(或者,以这种方式说 - 如果您需要将一个 class 更改为另一个),那么您可以轻松地做到这一点而无需努力了。

  2. 凝聚力指的是具有积极意义的东西。因此,正如您可能猜到的那样,您必须尝试以实现 High Cohesion 的方式构建您的应用程序。这是什么意思?它指的是应用程序的不同 模块 之间的交互。 例如,假设您的应用有两个模块:

    • 导出模块 - 将一些数据导出到 xml 文件
    • 导入模块 - 从 xml 文件中导入一些数据

如果导入模块几乎可以导入导出模块导出的所有内容,则说明您在它们之间建立了良好的交互,并且它们之间的内聚性很高。

耦合和内聚是软件模块的两种不同度量

耦合描述了如何两个classes相互作用。如果两个 class 相互依赖,则它们表现出 紧耦合 ;如果两个 class 可以彼此独立使用,则它们表现出 松散耦合 。首选松散耦合,因为它有助于实现可重用组件和高可维护性。

凝聚力描述了单个class的组成部分如何归为一体。 class 包含彼此无关的方法表现出 低内聚性 ; class 包含逻辑上相似的方法表现出 高内聚性 。高凝聚力导致专注于 class 服务于明确定义的目的。

耦合和内聚的关系是共生的。如果两个 class 紧密耦合,那么它们很可能没有明确的职责,因此会表现出低内聚性。相反,如果一个 class 是高度内聚的,它的目的是明确的,并且更容易以避免与它们耦合的方式与其他 class 一起使用。


对于您的特定任务,请从编写 "good" 代码开始 - 低耦合和高内聚。要将其转变为低耦合和低内聚的东西,请保持 classes 彼此独立,但将功能洗牌。使用一大堆不相关的方法创建实用程序 class。将所有以元音字母开头的方法放入另一个class。做一些事情来阻止任何class有明确的目的。

只要您不让 classes 相互依赖 ,您所创建的代码既表现出低耦合性,又具有低内聚性。

内聚和耦合是您组织项目的方式的属性。

举个物理例子。现在假设你有棒球、网球、板球、槌球、长曲棍球和台球。假设您还有棒球棒、网球拍、板球拍、槌球槌、长曲棍球棒和台球杆。如果您要将这 12 个对象随机分类为 6 个袋装对象对,您可能会有一个低耦合和低内聚的组织。具体来说,假设包含六个袋子:

  1. 棒球、台球杆
  2. 长曲棍球、网球拍
  3. 台球、板球拍
  4. 网球、棒球​​棒
  5. 槌球、长曲棍球棒
  6. 板球、槌球槌

这个组织的内聚性很低,因为每个包中的对象都是不相关的。这个组织有适度的耦合,因为不同包的内容之间的关系密度是中等的(但像意大利面条一样)——六个链接(每个运动球棒对一个)可能有 21 个。如果你想要一个偶数的例子较低的耦合你可以从更多的运动对象对开始

物品明显组织成袋

  1. 棒球,棒球棒
  2. 网球、网球拍
  3. 板球、板球拍
  4. 槌球,槌球槌
  5. 长曲棍球、长曲棍球棒
  6. 台球、台球杆

具有更低的耦合度(零耦合),因为 none 的包内容与其他包的内容相关。它具有很高的内聚性,因为一个包内的内容是相互关联的。

简而言之:

软件工程中的凝聚力,就像在现实生活中一样,是指组成一个整体(在我们的例子中,我们假设 class)的元素在多大程度上可以说它们实际上属于一起。因此,它衡量的是软件模块源代码所表达的每项功能的相关性有多强。

从 OO 的角度来看内聚的一种方法是 class 中的方法是否使用任何私有属性。

现在的讨论比这更大,但是高内聚(或内聚的最佳类型 - 功能内聚)是指模块的各个部分被分组,因为它们都有助于模块的一个明确定义的任务。

用简单的话来说,耦合是一个组件(同样,想象一个 class,尽管不一定)对另一个组件的内部工作或内部元素了解多少,即它对另一个组件有多少了解其他组件。

松散耦合是一种将系统或网络中的组件互连的方法,以便这些组件在实际可能的最小程度上相互依赖……

长:

I wrote a blog post about this. 它通过示例等详细讨论了所有这些内容。它还解释了为什么应该遵循这些原则的好处。我认为它可以帮助...