凝聚力和耦合
内聚和耦合有什么区别?
耦合和内聚如何导致软件devise的好坏?
什么是一些例子,概述了两者之间的差异,以及它们对整体代码质量的影响?
凝聚力是指类(或模块)可以做什么。 低凝聚力意味着class级做了各种各样的行动 – 范围广泛,不重视应该做什么。 高凝聚力意味着class级专注于应该做什么,即只有与class级意图有关的方法。
低内聚的例子:
------------------- | Staff | ------------------- | checkEmail() | | sendEmail() | | emailValidate() | | PrintLetter() | -------------------
高内聚的例子:
---------------------------- | Staff | ---------------------------- | -salary | | -emailAddr | ---------------------------- | setSalary(newSalary) | | getSalary() | | setEmailAddr(newEmail) | | getEmailAddr() | ----------------------------
至于耦合 ,它是指两个类/模块相互关联或相关的方式。 对于低年级的学生来说,改变一个class级的专业不应该影响另一个class级。 高耦合会使得难以改变和维护你的代码; 因为课程紧密结合在一起,所以做出改变可能需要整个系统的改进。
良好的软件devise具有很高的内聚性和低耦合性 。
模块之间的高内聚和模块之间的低耦合通常被认为与OO编程语言的高质量有关。
例如,每个Java类中的代码必须具有较高的内部凝聚力,但是尽可能与其他Java类中的代码松散耦合。
迈耶面向对象软件构build(第二版)第三章对这些问题进行了很好的描述。
增加凝聚力和减less耦合确实导致了良好的软件devise。
凝聚力将您的function划分为简洁和最接近与其相关的数据,而去耦则确保function实现与系统的其他部分隔离。
解耦允许您更改实现而不影响软件的其他部分。
凝聚力确保实现更具体的function,同时更容易维护。
减less耦合和增加内聚的最有效的方法是通过界面进行devise 。
那就是主要的function对象应该只通过它们实现的接口“彼此认识”。 接口的实现引入了凝聚力作为自然结果。
虽然在一些讲座中不太现实,但应该是devise目标。
例子(很简单):
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 } }
在你的代码库的其他地方,你可以有一个处理问题的模块,不pipe它们是什么:
public class OtherModuleProcessor { public void Process(List<IStackoverflowQuestion> questions) { ... process each question. } }
凝聚力是一个软件元素如何相关和集中的责任。
耦合是指软件元素与其他元素的连接程度。
软件元素可以是类,包,组件,子系统或系统。 在devise系统时,build议使用具有高内聚性和支持低耦合的软件元素。
低凝聚力导致难以维持,理解和减less重复使用的单一类别。 同样, 高耦合导致紧密耦合的类,并且变化趋向于不是非本地的,难以改变并且减less重用。
我们可以假设我们正在devise一个具有以下要求的典型监视器的ConnectionPool
。 请注意,它可能看起来像一个简单的类如ConnectionPool
太多,但基本的意图只是为了演示一个简单的例子低耦合和高凝聚力 ,我认为应该有所帮助。
- 支持获得连接
- 释放连接
- 获取有关连接与使用计数的统计信息
- 获取有关连接与时间的统计信息
- 将连接检索和发布信息存储到数据库以供稍后进行报告。
在低内聚的情况下,我们可以devise一个ConnectionPool
类,把所有这些function/职责强制填充到一个类中,如下所示。 我们可以看到,这个单独的类负责连接pipe理,与数据库交互以及维护连接统计信息。
通过高度凝聚力,我们可以将这些责任分配到各个class级,使其更具可维护性和可重用性。
为了演示低耦合,我们将继续上面的高内聚的ConnectionPool
图。 如果我们看上面的图,尽pipe它支持高内聚性, ConnectionPool
与ConnectionStatistics
类和PersistentStore
紧密耦合,它直接与它们交互。 相反,为了减less耦合,我们可以引入一个ConnectionListener
接口,让这两个类实现接口,让它们注册到ConnectionPool
类。 ConnectionPool
将迭代这些监听器,并通知它们连接获取和释放事件,并允许较less的耦合。
注意/单词或警告:对于这个简单的情况,它可能看起来像一个矫枉过正,但是如果我们想象一个实时的情况下,我们的应用程序需要与多个第三方服务进行交互,以完成一个事务:直接耦合我们的代码与第三方服务意味着第三方服务的任何变化都可能导致我们的代码在多个地方发生变化,相反,我们可以使Facade
与这些多个服务在内部进行交互,而对服务的任何更改都将成为Facade
本地服务,并强制与第三方服务。
凝聚力的最佳解释来自Bob叔叔的Clean Code:
类应该有less量的实例variables。 每个类的方法都应该处理一个或多个这些variables。 一般来说,一个方法操作的variables越多,该方法对其类的内聚性越强 。 每个方法使用每个variables的类是最大程度上内聚的。
一般来说,build立这种最大程度的凝聚力的课程既不可取也不可能; 另一方面, 凝聚力高 。 当凝聚力高时,就意味着这个阶级的方法和variables是相互依存的,作为一个逻辑的整体凝聚在一起。
保持函数较小并保持参数列表较短的策略有时会导致方法子集使用的实例variables的激增。 发生这种情况时,几乎总是意味着至less有一个class级试图摆脱大class。 你应该尝试把variables和方法分成两个或更多的类,这样新的类更具有内聚性。
软件工程中的凝聚力是某个模块的元素所属的程度。 因此,这是衡量软件模块的源代码所expression的每个function有多强烈的相关性的度量。
用简单的话来说,一个组件是多less(再一次,设想一个类,尽pipe不一定)知道另一个组件的内部运作或内部组件,也就是说它有多less关于另一个组件的知识。
我写了一篇关于这个的博客文章 ,如果你想通过例子和图纸阅读更多的细节。 我认为它回答了你的大部分问题。
凝聚力是模块内部关系的表征。
耦合是模块之间关系的指示。
检查这个链接
我认为可以把这些差异放在下面:
- 内聚表示代码库的一部分形成一个逻辑单一的primefaces单元的程度。
- 耦合表示一个单位独立于其他单位的程度。
- 在不破坏凝聚力的情况下完全解耦是不可能的,反之亦然。
在这篇博客文章中,我详细地写下了这篇文章 。
凝聚力表示模块的相对function强度。
- 一个有凝聚力的模块执行一项任务,与程序的其他部分中的其他部件几乎不需要交互。 简言之,一个有凝聚力的模块应该(理想地)只做一件事。
-
传统观点:
一个模块的“一心一意”
-
OOOO视图:
凝聚意味着一个组件或类只能封装彼此密切相关的属性和操作,并且只能封装类或组件本身
-
凝聚力水平
Functional
Layer
Communicational
Sequential
Procedural
Temporal
utility
耦合表示模块之间相对相互依赖。
-
耦合取决于模块之间的接口复杂性,进入或引用模块的点以及通过接口传递的数据。
-
常规视图:组件连接到其他组件和外部世界的程度
-
面向对象的观点:一个定性的度量,在哪个级别相互联系
-
耦合程度
Content
Common
Control
Stamp
Data
例程调用
使用types
包含或导入
外部#
我们希望相关的行为坐在一起,而不相关的行为坐在其他地方。 为什么? 那么,如果我们想改变行为,我们希望能够在一个地方改变它,并尽快释放这个改变。 如果我们必须在很多不同的地方改变这种行为,我们将不得不释放许多不同的服务(可能在同一时间)来实现这一改变。 在很多不同的地方进行更改比较慢,而且一次部署大量的服务是有风险的 – 我们要避免这两个方面。 所以我们希望在我们的问题领域内find有助于确保相关行为在一个地方的边界。 – 凝聚力
并尽可能松散地与其他边界沟通。 – 耦合
耦合 =两个模块之间的交互/关系… 内聚 =模块内两个元素之间的交互。
一个软件由许多模块组成。 模块由元素组成。 考虑一个模块是一个程序。 程序中的函数是一个元素。
在运行时,程序的输出被用作另一个程序的input。 这被称为模块到模块的交互或进程来处理通信。 这也被称为耦合。
在一个程序中,函数的输出被传递给另一个函数。 这称为模块内元素的交互。 这也被称为凝聚力。
例:
耦合 =在两个不同的家庭之间进行沟通…… 凝聚力 =在家庭中的父母之间的沟通。
一般而言,内聚是类中所有方法听起来相似,并经常超载的地方。 例如:
MyClass { displayCar(); displayCarMinimized(); displayCarSpecialised(); display(Vehicle v) display(Vehicle v, Country c) displayAll() }