【发布时间】:2015-06-28 04:39:17
【问题描述】:
我应该编写相同代码的两个版本。一个具有 low 耦合和 high 内聚,另一个仍然具有 low 耦合但这次具有 low 内聚。我真的不明白有什么区别?我怎样才能有低耦合和低内聚?它们似乎如此相关,以至于这是不可能的。
有人可以解释一下吗?也许举个例子? 谢谢!
【问题讨论】:
我应该编写相同代码的两个版本。一个具有 low 耦合和 high 内聚,另一个仍然具有 low 耦合但这次具有 low 内聚。我真的不明白有什么区别?我怎样才能有低耦合和低内聚?它们似乎如此相关,以至于这是不可能的。
有人可以解释一下吗?也许举个例子? 谢谢!
【问题讨论】:
简而言之:
软件工程中的凝聚力,就像在现实生活中一样,是指构成一个整体(在我们的例子中假设一个类)的元素在多大程度上可以说它们实际上属于一起。因此,它是衡量一个软件模块的源代码所表达的每个功能的关联程度。
从 OO 角度看待内聚的一种方法是类中的方法是否使用任何私有属性。
现在讨论的范围远不止于此,但高内聚(或内聚的最佳类型 - 功能内聚)是将模块的各个部分组合在一起,因为它们都有助于模块的单个明确定义的任务。
简单地说,耦合是一个组件(再次,想象一个类,虽然不一定)对另一个组件的内部工作或内部元素了解多少,即它对另一个组件了解多少。
松散耦合是一种互连系统或网络中的组件的方法,以便这些组件在实际可能的最小范围内相互依赖......
长篇大论:
I wrote a blog post about this. 它通过示例等详细讨论了所有这些。它还解释了为什么应该遵循这些原则的好处。我认为它可以帮助...
【讨论】:
耦合和内聚是软件模块的两种不同的衡量标准。
耦合是对两个类如何交互的描述。如果两个类相互依赖,它们就表现出紧耦合;如果两个类可以彼此独立使用,则它们表现出松散耦合。松散耦合是首选,因为它适用于可重用组件和高可维护性。
内聚是对一个单个类的组件如何归属的描述。包含彼此无关的方法的类表现出低内聚力;包含逻辑上相似的方法的类表现出高内聚性。高内聚力会导致目标明确的重点课程。
耦合和内聚的关系是共生的。如果两个类紧密耦合,那么它们很可能没有明确的职责,因此会表现出低内聚性。相反,如果一个类是高度内聚的,那么它的目的是明确定义的,并且可以更容易地与其他类一起使用,避免与它们耦合。
对于您的特定任务,从编写“好的”代码开始 - 低耦合和高内聚。要将其转变为低耦合和低内聚的东西,请保持类彼此独立,但要对功能进行洗牌。用一大堆不相关的方法创建一个 Utility 类。将所有以元音开头的方法放到另一个类中。做一些事情 阻止任何类有一个明确的目的。
只要您避免类相互依赖,您就可以创建表现出低耦合但也具有低内聚性的代码。
【讨论】:
内聚和耦合是您组织项目的属性。
让我们举一个物理例子。现在假设你有一个棒球、网球、板球、槌球、长曲棍球和台球。假设您还有棒球棒、网球拍、板球棒、槌球槌、曲棍球棒和台球杆。如果你将这 12 个对象随机分类为 6 个袋装对象对,你可能会得到一个低耦合和低内聚的组织。具体来说,假设包含六个袋子:
这种组织的凝聚力很低,因为每个包中的对象是不相关的。这个组织有适度的耦合,因为不同包的内容之间的关系密度是中等的(但像意大利面条一样)——可能有 21 个链接的六个链接(每个运动球棒对一个)。如果你想要一个偶数的例子较低的耦合可以从更多的运动对象对开始
将物品明显组织成袋子
具有更低的耦合(零耦合),因为没有一个包内容与其他包的内容相关。由于包内的内容相互关联,因此具有很高的凝聚力。
【讨论】:
耦合和内聚在某种程度上是两个接近的概念,但并不相同。你的设计应该有:
低耦合:这意味着您的类不应过多地依赖于其他类(尤其是具体类)。您必须尽可能将它们解耦。解耦有助于可重用性(OO 软件工程的目标)。因为当您重用此类类时,您无需将任何其他类与您的类一起使用即可使其工作。 Facade 等许多设计模式都实现了这一目标。
高凝聚力:这意味着您的课程不应包含许多不相关的任务。当您增加凝聚力时,代码理解变得更容易,因为该类正在执行一些连贯的任务。这也增加了可重用性。一些设计模式,如Visitor 就是有这个目标的。
在继续,我给出了 3 个可能更有意义的类示例:
#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() { /*...*/ }
};
【讨论】:
例如,假设您有两个类,它们只有在两个类都存在时才能工作。类中功能的相似性称为内聚,事物如何属于在一起,但它们如何交互称为耦合。
因此,如果您编写的程序具有低耦合和高内聚性,则意味着程序的类易于使用和重用,并且类的内部属于同一类。所以类中充满了显示相似性的方法。
通过这种方式,更改程序的一部分相当容易,而无需在多个位置更改整个代码。因此,耦合通常是描述实现难易程度的术语,内聚用于衡量类中方法之间的相似性。因此,如果您想构建低耦合和低内聚的东西,您将不得不构建一些易于在程序中实现但会破坏封装的东西。
【讨论】:
区别在于含义。
耦合指的是具有否定意义的事物。因此,根据SOLID 规则,您必须尝试以松散耦合的方式构建您的应用程序。 例如,Gof patterns(例如,Abstract Factory)和DI containers(例如 .NET 世界中的 MS Unity 或 NInject)可以帮助您实现这一目标。 松耦合代码意味着如果您需要将新类插入到您的应用程序中(或者,假设以这种方式 - 如果您需要将一个类更改为另一个),那么您可以轻松地完成它而无需付出很大的努力。
凝聚力指的是具有积极意义的事物。因此,您可能已经猜到了,您必须尝试以这样的方式构建您的应用程序,以实现高内聚。这是什么意思?它指的是应用程序的不同模块 之间的交互。 例如,假设您的应用有两个模块:
如果 Import 模块几乎可以成功导入 Export 模块导出的所有内容,则说明您在它们之间建立了良好的交互,并且它们之间的内聚度很高。
【讨论】:
它们是相反的,低耦合 = 高内聚。
【讨论】: