2010-06-21 218 views
291

凝聚力和耦合力有什么区别?凝聚力和耦合力

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

什么是一些例子,概述了两者之间的差异,以及它们对整体代码质量的影响?

+1

检查出来:http://msdn.microsoft.com/en-us/magazine/cc947917。aspx – Inv3r53 2010-06-21 14:03:37

+1

我想指出这篇文章:[S.O.L.I.D.软件开发,一步到位](http://www.code-magazine.com/article.aspx?quickid=1001061&page=1)。 Grz,克里斯。 – XIII 2010-06-21 14:40:07

+3

[This](http://enterprisecraftsmanship.com/2015/09/02/cohesion-coupling-difference/)是关于此主题的最新帖子 – janisz 2015-09-02 12:22:00

回答

431

凝聚力指的是类(或模块)能够做什么。低凝聚力意味着班级做了各种各样的行动 - 范围广泛,不重视应该做什么。高凝聚力意味着班级专注于应该做什么,即只有与班级意图有关的方法。低凝聚力的

实施例:

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

高凝聚力的实施例:

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

至于耦合,它指的是如何相关的或依赖两个类/模块是朝向彼此。对于低年级的班级,改变某一班的主修课不应该影响其他班。高耦合会导致难以改变和维护你的代码;因为课程紧密结合在一起,所以做出改变可能需要整个系统改造。

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

+0

@ mauris.sg我试图围绕低耦合程度的低点以及凝聚力应该有多高。我有一个快速的问题。可以说我正在构建一个REST API。如果一个REST URL的一部分由一个类A表示,并且其他调用从这个部分分散到不同的类中,考虑到这些形成子树S,可以肯定地说A类代表低耦合和高内聚性它也被视为一个绑定子树S的组?即我可以在A本身内调用表示A之外的不同端点的类吗? 我希望我不是模糊的。 – Setafire 2014-08-05 22:57:14

+0

@ mauris.sg或者A可以是代表REST调用本身的构建器,也可以作为其子树S的组来使用。很抱歉,这个问题可能看起来很长,但前者是我的团队主管坚持要做的事情,尽管我没有真正从中获得价值。 – Setafire 2014-08-05 23:03:51

+4

我不明白如何删除一些方法,并添加一些其他方法增加内聚力。有人可以帮忙吗? – 2016-01-27 09:44:07

54

高内聚内模块和低耦合模块之间往往被视为背景下的面向对象编程语言的高品质。例如,每个Java类中的代码必须具有较高的内部凝聚力,但尽可能与其他Java类中的代码松散耦合。

Meyer's Object-Oriented Software Construction (2nd edition)的第3章是对这些问题的很好的描述。

30

增加凝聚力和减少耦合确实导致良好的软件设计。

内聚将您的功能划分为简洁和最接近与其相关的数据,而分离可确保功能实现与系统其余部分隔离。

解耦允许您在不影响软件其他部分的情况下更改实现。

凝聚力确保实施更具体到功能,同时更容易维护。

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

这是主要的功能对象应该只通过它们实现的接口互相“认识”。接口的实现引入了凝聚力作为自然结果。

虽然在一些senarios中不现实,但它应该是一个设计目标。

例(非常粗略的):

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. 
    } 
} 
11

凝聚力软件工程是某个模块的元素所属的程度。因此,它是衡量软件模块的源代码所表达的每个功能有多强烈关联的度量。用简单的话来说,一个组件(同样,想象一个类,尽管不一定)知道另一个组件的内部运作或内部组件,即它对另一个组件有多少知识。

I wrote a blog post about this,如果你想通过例子和图纸阅读更多的细节。我认为它回答了你的大部分问题。

16
凝聚力

最好的解释来自鲍勃叔叔的干净代码:

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

一般来说,既不可能也不可能创建这样的最大粘性类;另一方面,想凝聚力高。当凝聚力很高时,这意味着这个阶级的方法和变量是相互依存的,并且作为一个逻辑整体在一起。

保持函数较小并保持参数列表较短的策略有时会导致方法子集使用的实例变量激增。发生这种情况时,几乎总是意味着至少有一个班级试图摆脱大班级。你应该尝试把变量和方法分成两个或更多的类,这样新的类更加紧密。

1

我认为差异可以被置为执行以下操作:

  • 衔接表示到其上的代码库的一部分形成了一个单一的逻辑,原子单元的程度。
  • 耦合表示单个单元独立于其他单元的程度。
  • 在不破坏凝聚力的情况下完全解耦是不可能的,反之亦然。

In this blog post我写了更详细的内容。

0

凝聚力表示模块的相对功能强度。

  • 一个内聚模块执行一项任务,需要很少的 与程序其他部分的其他组件交互。简单地说,一个有凝聚力的模块应该(理想地)只做一件事。
  • Conventional视图:

    “单意识”的模块的

  • OO视图:

    cohesion意味着一个部件或类只封装属性和操作是密切相互关联以及相关类别或组件本身

  • 内聚力水平

    Functional

    Layer

    Communicational

    Sequential

    Procedural

    Temporal

    utility

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

  • 耦合取决于模块之间的接口的复杂性,在该条目或参考的 点到模块制成,并且什么数据 跨越接口通过。

  • 传统观点: 的程度的部件被连接到其他部件和外部世界

  • OO视图:度定性度量给哪些类被连接到彼此

  • 级耦合的

    Content

    Common

    Control

    Stamp

    Data

    Routine呼叫

    Type使用

    Inclusion或导入

    External#

26

凝聚力表示软件元素的职责是如何相关和集中的。

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

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

低凝聚力导致难以维护,理解和减少重复使用的单片类。类似地,高耦合会导致类型紧密耦合,并且更改倾向于不是非本地,难以更改并减少重用。

我们可以假设我们正在设计具有以下要求的典型监视器ConnectionPool。请注意,它可能看起来像一个简单的类如ConnectionPool太多,但基本意图只是示范低耦合高内聚与一些简单的例子,我认为应该帮助。

  1. 支持获取连接
  2. 释放连接
  3. 获取有关连接VS使用次数
  4. 获得统计数据有关连接与时间
  5. 存储连接检索和发布信息的数据库,报表统计数据后来。

随着低凝聚力我们可以通过强制馅所有这些功能设计ConnectionPool类/责任到下面的类。我们可以看到,这个单独的类负责连接管理,与数据库交互以及维护连接统计信息。

Low Cohesion Connection Pool

随着高内聚我们可以分配跨越类这些责任,并使其更容易维护和重用。

High Cohesion Connection Pool

为了证明低耦合,我们将继续与高凝聚力上述ConnectionPool图。如果我们看上面的图表,虽然它支持高凝聚力,但ConnectionPoolConnectionStatistics类别和PersistentStore紧密耦合,它直接与它们交互。相反,为了减少耦合,我们可以引入一个ConnectionListener接口,让这两个类实现接口并让它们在ConnectionPool类中注册。 ConnectionPool将遍历这些监听器,并通知它们连接获取和释放事件,并允许更少的耦合。

Low Coupling ConnectionPool

注/ Word或警告:对于这个简单的场景它可能看起来像矫枉过正,但如果我们想象到我们的应用程序需要与多个第三方服务交互完成一个实时情景事务:直接将我们的代码与第三方服务耦合意味着第三方服务中的任何更改都可能导致我们的代码在多个位置发生更改,相反,我们可以在内部与这些多个服务进行交互,并对服务进行任何更改成为本地的Facade并强制与第三方服务的低耦合。

+2

优秀的答案!如果可能的话,你可以使用其他的例子吗?连接池可能并不是每个人都清楚的。无论如何,它确实帮助了我。那谢谢啦! – 2016-01-27 09:56:45

+0

如何使用ConnectionListener接口帮助减少耦合?您可以提供一个更易于理解的示例。 – 2016-04-30 19:12:43

+0

@abhishekgupta在这个例子中,您可能已经注意到我们已经使用观察者模式来实现低/松耦合。通过这将有助于[观察者如何创建松散耦合设计?](http://programmers.stackexchange.com/questions/234230/how-does-observer-create-loosely-coupled-design) – 2016-05-01 04:36:07

0

耦合两个模块之间 =相互作用/关系... 衔接 =一个模块内的两个元素之间的相互作用。

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

在运行时,程序的输出被用作另一个程序的输入。这称为模块到模块的交互或进程来处理通信。这也被称为耦合。

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

例子:

耦合在2间不同的家庭 =通信... 凝聚力 =在父亲的母子之间的家庭内部通信。

+0

那么,你如何解释它们对软件的影响?** – 2016-11-19 19:23:00

+0

一个软件包含许多模块。模块由元素组成。考虑一个模块是一个程序。程序中的函数是一个元素。 – 2016-12-04 03:12:00

14

凝聚力指示之间的关系模块。

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

enter image description here

检查this链接

0

我们希望有关的行为坐在一起,和无关的行为在其他地方坐。为什么?那么,如果我们想要改变行为,我们希望能够在一个地方改变它,并尽快释放这个改变。如果我们必须在很多不同的地方改变这种行为,我们将不得不释放许多不同的服务(可能在同一时间)来实现这种改变。在很多不同的地方进行更改比较慢,而且立即部署大量服务存在风险 - 我们希望避免这两种情况。所以我们希望找到问题领域内的边界,以帮助确保相关行为集中在一个地方。 - 凝聚力

,并与其他边界为松散地沟通。 - 耦合

0

凝聚(凝聚):这意味着一起HESION这意味着。将不同物质的粒子粘在一起的系统。

对于现实生活中的例子:
enter image description here
img Courtesy

整体大于部分 - 亚里士多德的总和。

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

  • 耦合通常与凝聚力对比。低耦合通常与高内聚力相关,反之亦然。低耦合通常表明结构良好的计算机系统和良好的设计,并且与高内聚性相结合时,支持高可读性和可维护性的总体目标。 wiki