内聚和耦合之间有什么区别?
耦合和凝聚力如何导致软件设计的好坏?
有哪些示例概述了两者之间的差异以及它们对整体代码质量的影响?
内聚和耦合之间有什么区别?
耦合和凝聚力如何导致软件设计的好坏?
有哪些示例概述了两者之间的差异以及它们对整体代码质量的影响?
Answers:
内聚性是指类(或模块)可以做什么。缺乏凝聚力意味着班级会采取各种各样的行动-范围很广,没有专注于应该做什么。高凝聚力意味着班级专注于应该做的事情,即只涉及班级意图的方法。
低内聚力示例:
-------------------
| Staff |
-------------------
| checkEmail() |
| sendEmail() |
| emailValidate() |
| PrintLetter() |
-------------------
高内聚力示例:
----------------------------
| Staff |
----------------------------
| -salary |
| -emailAddr |
----------------------------
| setSalary(newSalary) |
| getSalary() |
| setEmailAddr(newEmail) |
| getEmailAddr() |
----------------------------
至于耦合,它是指两个类/模块彼此之间如何相关或相依。对于低耦合类,更改一个类中的主要内容不应影响另一类。高耦合将使更改和维护代码变得困难;由于类紧密结合在一起,因此进行更改可能需要对整个系统进行改造。
好的软件设计具有高凝聚力和低耦合性。
set
与get
功能说明功能,更具体的“工作人员”语境-高特异性给予该例如其较高的凝聚力。
内聚性是模块内关系的指示。
耦合是模块之间关系的指示。
凝聚
耦合
检查此链接
在OO编程语言中,模块内的高凝聚力和模块之间的低耦合通常被认为与高质量有关。
例如,每个Java类中的代码必须具有较高的内部凝聚力,但应尽可能松散地耦合到其他Java类中的代码。
Meyer的面向对象软件构造(第2版)的第3章很好地描述了这些问题。
内聚性表明软件元素的职责之间如何相关和集中。
耦合是指软件元素与其他元素的连接强度。
该软件元素可以是类,包,组件,子系统或系统。并且在设计系统时,建议使用具有高内聚力并支持低耦合的软件元素。
低内聚性导致难以维护,理解和减少重用性的整体类。同样,高耦合导致紧密耦合的类,并且更改往往不是局部的,难以更改的,并减少了重用。
我们可以假设一个场景,在该场景中,我们设计ConnectionPool
具有以下要求的典型可监控显示器。请注意,对于像这样的简单类来说可能看起来太多了,ConnectionPool
但是基本目的只是通过一些简单的示例展示低耦合和高内聚性,我认为应该有所帮助。
在低内聚性的情况下,我们可以ConnectionPool
通过将所有这些功能/职责强制填充到单个类中来设计一个类,如下所示。我们可以看到,该类负责连接管理,与数据库交互以及维护连接统计信息。
凭借高度的凝聚力,我们可以在各个类中分配这些责任,并使之更加可维护和可重用。
为了演示低耦合,我们将继续ConnectionPool
上面的高内聚图。如果我们看上图,尽管它支持很高的内聚性,但它ConnectionPool
与ConnectionStatistics
类紧密耦合,并且PersistentStore
直接与它们交互。相反,为了减少耦合,我们可以引入一个ConnectionListener
接口,让这两个类实现该接口并让它们在ConnectionPool
类中注册。然后,ConnectionPool
will将遍历这些侦听器,并通知他们连接获取和释放事件,并减少耦合。
注意/文字或注意事项:对于这种简单的情况,可能看起来有些过头,但是如果我们想象一个实时情况,其中我们的应用程序需要与多个第三方服务进行交互以完成交易:将代码直接与第三方服务耦合意味着第三方服务的任何更改都可能导致我们在多个地方的代码发生更改,相反,我们可以让Facade
这些代码在内部与这些多个服务进行交互,并且对服务的任何更改都将成为本地的,Facade
并与第三方进行低耦合服务。
内聚性的提高和耦合的减少确实导致了良好的软件设计。
内聚力对您的功能进行分区,以使其简洁明了且最接近与之相关的数据,而去耦则确保功能实现与系统的其余部分隔离。
通过解耦,您可以更改实现,而不会影响软件的其他部分。
内聚性确保实现更特定于功能,同时更易于维护。
通过界面设计是减少耦合和增加内聚力的最有效方法。
那就是主要功能对象应该只通过它们实现的接口相互“了解”。接口的实现自然会引入内聚性。
尽管在某些情况下不现实,但应该将其作为设计目标。
示例(非常粗略):
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.
}
}
凝聚力的最佳解释来自鲍伯叔叔的《清洁法》:
类应具有少量实例变量。类的每个方法都应操纵这些变量中的一个或多个。通常,方法操纵的变量越多,该方法对其类别的凝聚力就越大。每个方法使用每个变量的类具有最大的内聚性。
通常,创建此类最大内聚的类既不建议也不可行。另一方面,我们希望凝聚力很高。当内聚性很高时,这意味着该类的方法和变量是相互依赖的,并且作为逻辑整体挂在一起。
保持函数较小和保持参数列表简短的策略有时会导致方法子集使用的实例变量激增。发生这种情况时,几乎总是意味着至少还有另一个班级试图脱离更大的班级。您应该尝试将变量和方法分为两个或多个类,以使新类具有更高的凝聚力。
简单来说,内聚表示代码库的一部分形成逻辑上单个原子单元的程度。另一方面,耦合表示单个单元彼此独立的程度。换句话说,它是两个或多个单元之间的连接数。数量越少,耦合越低。
本质上,高凝聚力意味着将彼此相关的代码库部分放在一个地方。同时,低耦合意味着尽可能地分离代码库的无关部分。
从内聚和耦合的角度来看,代码类型:
理想的是遵循准则的代码。它是松散耦合的,并且具有高度的凝聚力。我们可以用下面的图片说明这样的代码:
God Object是引入高凝聚力和高耦合的结果。它是一种反模式,基本上代表单个代码,可一次完成所有工作: 当选择不同类或模块之间的边界时,选择不当就会发生。
破坏性的去耦是最有趣的一种。有时,当程序员试图使代码库脱钩而使代码完全失去其焦点时,有时会发生这种情况:
在这里阅读更多
软件工程中的内聚性是某个模块的元素所属的程度。因此,它衡量了由软件模块的源代码表达的每个功能之间的关联程度。
简单来说,耦合就是一个组件(尽管不是必须的,再想一想一个类)对另一组件的内部运作或内部元素了解多少,即它对另一组件具有多少知识。
我写了一篇有关此的博客文章,如果您想阅读更多有关示例和图纸的详细信息。我认为它回答了您的大多数问题。
内聚力是模块相对功能强度的指标。
常规视图:
模块的“一心一意”
OO视图:
内聚意味着组件或类仅封装彼此之间以及与类或组件本身密切相关的属性和操作
凝聚力水平
功能
层
通讯
顺序
程序
时间
效用
耦合表示模块之间的相对相互依赖性。
耦合取决于模块之间的接口复杂性,对模块进行输入或引用的时间点以及通过接口传递的数据。
传统视图:组件与其他组件以及与外部世界的连接程度
面向对象视图:对类之间相互连接程度的定性度量
耦合程度
内容
普通
控制
邮票
数据
常规通话
类型使用
包含或导入
外部编号
耦合 =两个模块之间的交互/关系... 内聚 =一个模块中两个元素之间的交互。
一个软件由许多模块组成。模块由元素组成。考虑模块是程序。程序中的功能是一个元素。
在运行时,程序的输出将用作另一个程序的输入。这称为模块间交互或过程间通信。这也称为耦合。
在单个程序中,一个函数的输出将传递给另一个函数。这称为模块内元素的交互。这也称为内聚力。
例:
耦合 = 2个不同家庭之间的交流... 内聚 =一个家庭中父子之间的交流。
术语凝聚力的确是有点反直觉的东西它是指在软件设计。
内聚力的共同含义是,可以很好地粘合在一起的东西是统一的,其特征是像分子吸引力那样的牢固结合。但是,在软件设计中,这意味着争取一个只做一件事的类,因此甚至不涉及多个子模块。
也许我们可以这样想。当零件是唯一零件时,它具有最大的凝聚力(仅做一件事,无法进一步分解)。这是软件设计中所需要的。凝聚力只是“单一责任”或“关注分离”的别称。
手上的耦合这个术语非常直观,这意味着当一个模块不依赖太多其他模块并且与其连接的模块可以很容易地替换时,例如遵循liskov替换原理。