题
凝聚力和耦合之间有什么区别?
耦合和凝聚力如何导致良好或差的软件设计?
哪些示例概述了两者之间的区别及其对整体代码质量的影响?
解决方案
凝聚 指类(或模块)可以做什么。低凝聚力将意味着班级采取各种各样的行动 - 它广泛,不关注该怎么做。高凝聚力意味着班级专注于应该做的事情,即仅与班级意图有关的方法。
低凝聚力的示例:
-------------------
| Staff |
-------------------
| checkEmail() |
| sendEmail() |
| emailValidate() |
| PrintLetter() |
-------------------
高凝聚力的示例:
----------------------------
| Staff |
----------------------------
| -salary |
| -emailAddr |
----------------------------
| setSalary(newSalary) |
| getSalary() |
| setEmailAddr(newEmail) |
| getEmailAddr() |
----------------------------
至于 耦合, ,它指的是两个类别/模块之间的相关或依赖性的相互关系。对于低耦合课程,改变一个班级的主要内容不应影响另一个类别。高耦合将使更改和维护您的代码变得困难;由于课程紧密地编织在一起,因此进行更改可能需要整个系统修改。
好的软件设计有 高凝聚力 和 低耦合.
其他提示
高凝聚力 之内 模块和低耦合 之间 模块通常被认为与OO编程语言中的高质量有关。
例如,每个Java类内部的代码必须具有很高的内部凝聚力,但在其他Java类中的代码尽可能松散。
第3章 迈耶的面向对象的软件构建(第二版) 是对这些问题的很好描述。
凝聚 是关系的迹象 之内 一个模块。
耦合 是关系的迹象 之间 模块。
凝聚
- 凝聚力是模块中关系的指示。
- 内聚会显示模块的相对功能强度。
- 凝聚力是组件 /模块关注单个事物的学位(质量)。
- 在设计时,您应该努力争取高内聚力,即一个粘性组件/模块专注于单个任务(即,一心一意),而与系统的其他模块几乎没有相互作用。
- 凝聚力是数据隐藏的一种自然扩展,例如,所有成员都可以看到具有默认可见性的软件包。凝聚力是内部 - 模块概念。
耦合
- 耦合是模块之间关系的指示。
- 耦合显示模块之间的相对依赖/相互依赖性。
- 耦合是组件 /模块连接到其他模块的程度。
- 在设计时,您应该为低耦合而努力,即模块之间的依赖性应更少
- 制作私人领域,私人方法和非公共课程可提供松散的耦合。
- 耦合是间模块概念。
查看 这 关联
凝聚 表明软件元素的责任是如何相关和集中的。
耦合 指软件元素与其他元素的连接程度。
软件元素可以是类,软件包,组件,子系统或系统。在设计系统时,建议使用具有的软件元素 高凝聚力 和支持 低耦合.
低内聚力 产生难以维持,理解和减少重新习惯的单片类别。相似地 高耦合 结果是紧密耦合的类,变化往往不是非本地的,难以更改和减少重复使用。
我们可以采用假设的情况,在其中设计一个典型的监视器 ConnectionPool
有以下要求。请注意,对于一个简单的课程,看起来太多了 ConnectionPool
但是基本意图只是证明 低耦合 和 高凝聚力 有了一些简单的例子,我认为应该有所帮助。
- 支持建立连接
- 释放连接
- 获取有关连接与使用计数的统计数据
- 获取有关连接与时间的统计数据
- 将连接检索存储并发布到数据库以供以后报告。
和 低内聚力 我们可以设计一个 ConnectionPool
通过将所有这些功能/责任塞入单个类中的类别,如下所示。我们可以看到,该单一类负责连接管理,与数据库进行交互以及维护连接统计数据。
和 高凝聚力 我们可以在整个课程中分配这些责任,并使其更可维护和重复使用。
展示 低耦合 我们将继续进行高凝聚力 ConnectionPool
上图。如果我们查看上图,尽管它支持高内聚力,否则 ConnectionPool
紧密结合 ConnectionStatistics
班级和 PersistentStore
它直接与他们互动。相反,为了减少耦合,我们可以引入一个 ConnectionListener
接口并让这两个类实现接口,让它们注册 ConnectionPool
班级。和 ConnectionPool
会通过这些听众迭代,并通知他们连接获得和发布事件,并允许更少的耦合。
注意/词或谨慎: 对于这种简单的情况,它看起来可能像是过度杀伤性,但是如果我们想象一个实时场景,我们的应用程序需要与多个第三方服务进行交互以完成交易:直接将代码与第三方服务耦合,则意味着任何更改第三方服务可能会在多个地方改变我们的代码,而是我们可以拥有 Facade
内部与这些多重服务互动,对服务的任何更改都成为本地的 Facade
并与第三方服务强制执行低耦合。
凝聚力增加和耦合减少确实会导致良好的软件设计。
凝聚力分区可分区您的功能,使其简洁,最接近与之相关的数据,同时解耦可确保功能实现与系统的其余部分隔离。
脱钩 允许您在不影响软件的其他部分的情况下更改实现。
凝聚 确保实施更具体地针对功能,同时更容易维护。
减少耦合和内聚力增加的最有效方法是 界面设计.
这是主要的功能对象,只能通过它们实现的接口“知道”。界面的实现引入了凝聚力,这是自然的结果。
尽管在某些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.
}
}
最好的解释 凝聚 来自鲍勃叔叔的干净代码:
类应具有少量的实例变量。类的每种方法都应操纵其中一个或多个变量。 通常,变量越多一种方法操纵方法的凝聚力越多. 。每种方法使用每个变量的类具有最大粘性。
通常,不建议创建这种最大的凝聚力类别。另一方面, 我们希望凝聚力很高. 。当凝聚力高时,这意味着类的方法和变量是共同依赖性的,并作为逻辑整体挂在一起。
保持功能较小和保持参数列表的策略有时会导致实例变量的扩散,这些变量由一部分方法使用。当这种情况发生时,几乎总是意味着至少还有其他班级试图摆脱较大的班级。您应该尝试将变量和方法分为两个或多个类别,以使新类更具凝聚力。
凝聚 在软件工程中是某个模块属于的元素所在的程度。因此,这是对软件模块的源代码表示的每个功能的强烈相关性的衡量标准。
耦合 简而言之,一个组件(再次,想象一个班级,尽管不一定)知道了另一个组件的内在工作或内部元素,即它对其他组件有多少知识。
我写了一篇博客文章, ,如果您想阅读更多详细信息,请示例和图纸。我认为它回答了您的大多数问题。
简单地, 凝聚 代表代码基库的一部分形成逻辑单一的原子单元的程度。 耦合, 另一方面,表示单个单元独立于其他单元的程度。换句话说,这是两个或多个单元之间的连接数量。数量越少,耦合越低。
从本质上讲,高凝聚力意味着将一部分在一个位置彼此相关的代码基础的一部分。同时,低耦合是要尽可能分开代码群的无关部分。
从凝聚力和耦合的角度来看的代码类型:
理想的 是遵循指南的代码。它是松散的耦合和高度凝聚力的。我们可以用这张图片说明这种代码:
上帝的对象 是引入高内聚力和高耦合的结果。它是一种反式模式,基本上代表一件立即完成所有工作的代码:
选择不佳 takes place when the boundaries between different classes or modules are selected poorly
破坏性的脱钩 是最有趣的。当程序员试图将代码基库解除太多以至于代码完全失去其焦点时,有时会发生这种情况:
阅读更多 这里
我认为差异可以如下:
- 凝聚力代表代码基库的一部分形成逻辑单一的原子单元的程度。
- 耦合表示单个单元独立于其他单元的程度。
- 在不损坏凝聚力的情况下,不可能完全归档完全脱钩,反之亦然。
在此博客文章中 我更详细地写下它。
凝聚 是模块的相对功能强度的指示。
- 凝聚力模块执行一个任务,需要在程序的其他部分中与其他组件几乎没有互动。简而言之,一个凝聚力的模块应该(理想情况下)只做一件事。
规定的观点:
模块的“一心一意”
OO视图:
粘合意味着组件或类仅封装了彼此紧密相关的属性和操作以及类或组件本身
凝聚力水平
功能
Layer
交流
序列
前后
时间
ut
耦合 是模块之间相对相互依存的指示。
耦合取决于模块之间的接口复杂性,对模块的输入或引用的点以及跨接口的哪些数据传递。
传统观点:组件与其他组件连接到外部世界的程度
oo View:一种定性衡量班级相互联系的程度
耦合水平
包含
通用
控制
踩踏
数据
通话
使用
包括或导入
外部#
耦合 =两个模块之间的互动 /关系...凝聚 =模块中两个元素之间的相互作用。
软件由许多模块组成。模块由元素组成。考虑一个模块是一个程序。程序中的功能是元素。
在运行时,程序的输出用作另一个程序的输入。这被称为模块交互或流程以处理通信的模块。这也称为耦合。
在单个程序中,函数的输出传递给另一个函数。这称为模块中元素的相互作用。这也称为凝聚力。
例子:
耦合 =在两个不同家庭之间进行沟通...凝聚 =家庭中父亲之间的沟通。
简单的说, 凝聚 意味着班级应代表一个概念。
如果所有类功能都与类代表的概念相关,则类的公共接口具有凝聚力。例如,拥有CashRegister和Coin功能的凝聚力不再是CashRegister类,而是将其分为两类 - CashRegister和Coin类。
在 耦合, ,一个类取决于另一个类,因为它使用了类的对象。
高耦合的问题在于它可以产生副作用。一个类别的一个更改可能会导致另一类的意外错误,并且可能会破坏整个代码。
通常,高内聚力和低耦合被认为是高质量的OOP。
术语 凝聚 确实对软件设计的含义确实有点直观。
凝聚力的共同含义是,结合在一起的事物是统一的,其特征是像分子吸引力这样的牢固键。但是,在软件设计中,这意味着要为理想情况下只能做一件事的课程而努力,因此甚至不涉及多个子模型。
也许我们可以这样想。当零件是唯一的部分时(只做一件事,不能进一步分解)时,零件具有最大的凝聚力。这是软件设计中所需的内容。凝聚力只是“单一责任”或“关注点分离”的另一个名称。
术语 耦合 手上非常直观 Liskov替代原则 .