首页 > 编程知识 正文

内聚和耦合是什么意思,耦合度和内聚度

时间:2023-05-04 22:55:45 阅读:135709 作者:2504

高聚集(High Cohesion ) )。

高凝聚是评价软件设计质量的另一个普遍标准。 凝聚,更专业的说法是功能凝聚,是软件系统中要素职责相关性和集中度的衡量。 如果元素具有高度相关的职责,且除这些职责内的任务外没有额外的工作,则该元素具有高聚集性,反之为低聚集性。 高内聚性要求软件系统中各要素有很高的合作性。 因为,我们要完成软件需求中的一个功能,可能需要做很多事情,而一个具有高度凝聚性的因素,就是只完成其职责内的事情,不在其职责内的事情就交给别人去完成。 这就是说,如果我是项目经理,我的工作就是监测和协调项目各个阶段的工作。 我的项目进入需求分析阶段后,委托需求分析师完成; 我的项目进入开发阶段后,委托软件开发者完成; 我的项目需要测试的时候,我会委托测试负责人。 如果我参与了开发,我就不是高凝聚的因素。 因为开发不是我的责任。 我们的项目为什么需要高度凝聚? 我认为可以从可读性、复用性、可维护性、易变更性四个方面来理解。

1 .可读性

一个人写文章、说话,条理清晰才容易理解。 这种情况也发生在读写软件代码中。 如果有很多代码写得乱七八糟,东跳西跳调用,读它的人会非常头疼。 这种事一直在写程序你和我可能都经历过。 如果每个类都是通过名称和说明明确理解其含义,而且类的每个属性和函数也很容易理解的任务和行为,那么这个程序的可读性必然会提高。 在软件产业越来越密集、软件产业中开发者合作越来越紧密、分工越来越细的今天,相信软件可读性的要求也越来越受到重视。

2 .可复用性

在软件开发中,最低层次的复用是码拷贝,其次是函数复用、对象复用、组件复用。 软件开发中最懒惰的人是最聪明的人,他们总是想着复用。 写代码的时候突然意识到某个功能是曾经实现过的功能,直接复制就可以了。 如果这个代码在同一个对象中,提交并编写函数到处调用就可以了。 如果不在同一个对象内,就抽象出来作为一个对象到处调用吧。 如果不在一个项目中,请将其作为组件引用到每个项目中。 代码复用在复用过程中使我们的代码精炼、健壮,提高代码质量。 代码复用确实给我们的开发带来了很多便利,但是一个代码能在需要的地方复用吗? 这对我们的软件开发质量提出了新的要求。 好的代码可以重用,坏的代码不行。 软件中的一个客体是一个凝聚性客体,如果能够保证软件中的一个客体可以在忽略与自身职能无关的其他任务的同时,执行自身职能范围内的各项任务,就可以保证其功能的相对独立性,脱离自身所处环境,可以复用到其他环境中

3 .维护性和易变更性

正如前面的《如何在struts+spring+hibernate的框架下构建低耦合高内聚的软件》所述,我们现在的软件在不断改变。 这个变更不仅来自我们的顾客,也来自我们的市场。 如果软件能通过更改及时满足市场需求,就能在市场竞争中获胜。 如何及时更改以适应我们的市场,是通过调整软件结构,使我们每次更改的成本最小,劳动力最小,这样的更改是最快最经济的。 高聚集的软件与各系统、模块和类的任务高度相关,因此可以最大限度地减少每次更改所涉及的范围。 例如,如果审阅表发生了更改,则只涉及审阅表的对象,而不会更改其他对象。 如果能做到这一点,我们的系统当然是维护性高、容易变更的系统。

那么,如何实现高凝聚呢? 以刚才提到的审查项目为例。 现在,为“审阅表单”的受众编写填写并保存审阅表单的代码。 受审核者的职责是更新和查询审核表中的数据,但在查看要填写的审核表时,必须显示审核计划的名称以及该审核计划需要哪些受审核者进行审核。 现在,如何编写代码来显示要填写的审阅表单? 是否要为受审核者的此函数编写用于查询审核计划和受审核者的代码? 如果那样做了,你的代码就不是高凝聚了。 因为查询审查计划和要审查的数据不是其责任。 正确的方法是要求“审阅计划”和“审阅者”对象完成这些工作,“审阅表单”对象只会得到结果。

此外,如果某个对象在自己的角色范围内,但进程要完成非常复杂的任务,则必须将其分解为几个功能相对独立的子函数来执行。 我看过朋友写的几百行函数,读起来很辛苦。 另外,这种函数中,有些是相对独立的代码,可以复用为其他代码,这是不可能的。 所以我给大家的建议是,不写太长的函数,超过一百行就考虑分解一些功能。

与“低偶联”一样,高聚集也不是绝对的,而是相对的指标,不能适度过度。 我们在现实生活中,如果在一个10人的小公司,每个人的分工可能会很粗,分配的职责会很广很杂。 那是因为整体的任务很少。 在一个两百人的大公司里,每个人的分工更精细,分配的任务更专业。 因为整体任务很多,所以为了提高效率需要专业分工。 软件开发也是如此,“审核计划”的对象必须完成的业务功能较少且不复杂,才能完全代为管理其子表“被审核方”和“审核方”。 但是,如果“审核计划”的对象必须完成的“管理审核计划表”基本职责中包含的业务功能过多或复杂,则应将“管理审核对象表”交给“被审核对象”的对象,并选择“管理审核人表” 同样,高凝聚性的维护性、容易变更只是相对的指标。 如果一个变更确实是大范围的变更,你就永远不行了

能通过内聚就不进行大范围的变更了。同时内聚也是要付出代价的,所以你也不必要去为了一个不太可能的变更去进行过度设计,应当掌握一个度。过度的内聚必将增加系统中元素之间的依赖,提高耦合度。所以“高内聚”与“低耦合”是矛盾的,必须权衡利弊,综合地去处理。在温婉的裙子等人翻译的《UML和模式应用》中,将内聚和耦合翻译为软件工程中的阴与阳,是中国人对内聚和耦合的最佳解释。

综上所述,“高内聚”给软件项目带来的优点是:可读性强、易维护和变更、支持低耦合、移植和重用性强。

低耦合(Low Coupling)

“低耦合”这个词相信大家已经耳熟能详,我们在看spring的书籍、MVC的数据、设计模式的书籍,无处不提到“低耦合、高内聚”,它已经成为软件设计质量的标准之一。那么什么是低耦合?耦合就是对某元素与其它元素之间的连接、感知和依赖的量度。这里所说的元素,即可以是功能、对象(类),也可以指系统、子系统、模块。假如一个元素A去连接元素B,或者通过自己的方法可以感知B,或者当B不存在的时候就不能正常工作,那么就说元素A与元素B耦合。耦合带来的问题是,当元素B发生变更或不存在时,都将影响元素A的正常工作,影响系统的可维护性和易变更性。同时元素A只能工作于元素B存在的环境中,这也降低了元素A的可复用性。正因为耦合的种种弊端,我们在软件设计的时候努力追求“低耦合”。低耦合就是要求在我们的软件系统中,某元素不要过度依赖于其它元素。请注意这里的“过度”二字。系统中低耦合不能过度,比如说我们设计一个类可以不与JDK耦合,这可能吗?除非你不是设计的Java程序。再比如我设计了一个类,它不与我的系统中的任何类发生耦合。如果有这样一个类,那么它必然是低内聚(关于内聚的问题我随后讨论)。耦合与内聚常常是一个矛盾的两个方面。最佳的方案就是寻找一个合适的中间点。

哪些是耦合呢?

1.元素B是元素A的属性,或者元素A引用了元素B的实例(这包括元素A调用的某个方法,其参数中包含元素B)。

2.元素A调用了元素B的方法。

3.元素A直接或间接成为元素B的子类。

4.元素A是接口B的实现。

幸运的是,目前已经有大量的框架帮助我们降低我们系统的耦合度。比如,使用struts我们可以应用MVC模型,使页面展现与业务逻辑分离,做到了页面展现与业务逻辑的低耦合。当我们的页面展现需要变更时,我们只需要修改我们的页面,而不影响我们的业务逻辑;同样,我们的业务逻辑需要变更的时候,我们只需要修改我们的java程序,与我们的页面无关。使用spring我们运用IoC(反向控制),降低了业务逻辑中各个类的相互依赖。假如类A因为需要功能F而调用类B,在通常的情况下类A需要引用类B,因而类A就依赖于类B了,也就是说当类B不存在的时候类A就无法使用了。使用了IoC,类A调用的仅仅是实现了功能F的接口的某个类,这个类可能是类B,也可能是另一个类C,由spring的配置文件来决定。这样,类A就不再依赖于类B了,耦合度降低,重用性提高了。使用hibernate则是使我们的业务逻辑与数据持久化分离,也就是与将数据存储到数据库的操作分离。我们在业务逻辑中只需要将数据放到值对象中,然后交给hibernate,或者从hibernate那里得到值对象。至于用Oracle、MySQL还是SQL Server,如何执行的操作,与我无关。

但是,作为优秀的开发人员,仅仅依靠框架提供的降低软件耦合的方法是远远不够的。根据我的经验,以下一些问题我们应当引起注意:

1)   根据可能的变化设计软件

我们采用职责驱动设计,设计中尽力做到“低耦合、高内聚”的一个非常重要的前提是,我们的软件是在不断变化的。如果没有变化我们当然就不用这么费劲了;但是如果有变化,我们希望通过以上的设计,使我们在适应或者更改这样的变化的时候,付出更小的代价。这里提供了一个非常重要的信息是,我们努力降低耦合的是那些可能发生变更的地方,因为降低耦合是有代价的,是以增加资源耗费和代码复杂度为代价的。如果系统中某些元素不太可能变更,或者降低耦合所付出的代价太大,我们当然就应当选择耦合。有一次我试图将我的表现层不依赖于struts,但发现这样的尝试代价太大而失去意义了。对于软件可能变更的部分,我们应当努力去降低耦合,这就给我们提出一个要求是,在软件设计的时候可以预判日后的变化。根据以往的经验我认为,一个软件的业务逻辑和采用的技术框架往往是容易变化的2个方面。客户需求变更是我们软件设计必须考虑的问题。在RUP的开发过程中,为什么需要将分析设计的过程分为分析模型和设计模型,愚以为,从分析模型到设计模型的过程实际上是系统从满足直接的客户需求到优化系统结构、适应可预见的客户需求变更的一个过程。这种客户需求的变更不仅仅指对一个客户需求的变更,更是指我们的软件从适应一个客户需求到适应更多客户需求的过程。另一个方面,现在技术变更之快,EJB、hibernate、spring、ajax,一个一个的技术像走马灯一样从我们脑海中滑过,我们真不知道明天我在用什么。在这样的情况下,适应变化就是我们最佳的选择。

2)   合理的职责划分

合理的职责划分,让系统中的对象各司其职,不仅是提高内聚的要求,同时也可以有效地降低耦合。比如评审计划BUS、评审表BUS、评审报告BUS都需要通过评审计划DAO去查询一些评审计划的数据,如果它们都去直接调用评审计划DAO(如图A),则评审计划BUS、评审表BUS、评审报告BUS三个对象都与评审计划DAO耦合,评审计划DAO一旦变更将与这三个对象都有关。在这个实例中,实际上评审计划BUS是信息专家(关于信息专家模式我将在后面讨论),评审表BUS和评审报告BUS如果需要获得评审计划的数据,应当向评审计划BUS提出需求,由评审计划BUS提供数据(如图B)。经过这样的调整,系统的耦合度就降低了。

3)   使用接口而不是继承

通过对耦合的分析,我们不难发现,继承就是一种耦合。如果子类A继承了父类B,不论是直接或间接的继承,子类A都必将依赖父类B。子类A必须使用在存在父类B的环境中,父类B不存在子类A就不能使用,这样将影响子类A的可移植性。一旦父类B发生任何变更,更改或去掉一个函数名,或者改变一个函数的参数,都将导致子类A不得不变更,甚至重写。假如父类B的子类数十上百个,甚至贯穿这个项目各个模块,这样的变更是灾难性的。这种情况最典型的例子是我们现在使用hibernate和spring设计DAO对象的方式,具体的描述参见我写的《如何在 struts + spring + hibernate的框架下构建低耦合高内聚的软件结构》一文。

总之,“低耦合”给软件项目带来的优点是:易于变更、易于重用。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。