对高内聚,低耦合的理解内聚:一个模块内各个元素彼此结合的紧密程度耦合:一个软件结构内不同模块之间互连程度的度量(耦合性也叫块间联系。
指软件系统结构中个模块间相互联系紧密程度的一种度量。
模块之间联系越紧密,其耦合性就越强,模块的独立性则越差,模块间耦合的高低取决于模块间接口的复杂性,调用的方式以及传递的信息。
)最近编码的时候,总是在犹豫是把某个方法封装在一个类里,还是单独的封装成一个类。
这让我突然想起内聚耦合这两个名词。
我们一直追求着,高内聚,低耦合。
对于低耦合,粗浅的理解是:一个完整的系统,模块与模块之间,尽可能的使其独立存在。
也就是说,让每个模块,尽可能的独立完成某个特定的子功能。
模块与模块之间的接口,尽量的少而简单。
如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分。
这样有利于修改和组合。
对于低耦合,我粗浅的理解是:在一个模块内,让每个元素之间都尽可能的紧密相连。
也就是充分利用每一个元素的功能,各施所能,以最终实现某个功能。
如果某个元素与该模块的关系比较疏松的话,可能该模块的结构还不够完善,或者是该元素是多余的。
内聚和耦合,包含了横向和纵向的关系。
功能内聚和数据耦合,是我们需要达成的目标。
横向的内聚和耦合,通常体现在系统的各个模块、类之间的关系,而纵向的耦合,体现在系统的各个层次之间的关系。
对于我在编码中的困惑,我是这样想的,用面向对象的思想去考虑一个类的封装。
一个方法,如何封装,拿到现实生活中来看,看这种能力(方法)是否是属于这类事物(类)的本能。
如果是,就封装在这个类里。
如果不是,则考虑封装在其它类里。
如果这种能力,很多事物都具有,则一定要封装在这类事物的总类里。
如果这种能力,很多事物都会经常用到,则可以封装成一个总类的静态方法。
关于耦合内聚的概念这些是软件工程中的知识,我上网查过,总结着几位大虾的评论,关于耦合的概念应该是这样的:1,对象之间的耦合度就是对象之间的依赖性.指导使用和维护对象的主要问题是对象之间的多重依赖性.对象之间的耦合性越高.维护成本越高.因此对象的设计应使类和构件之间的耦合最小.2,耦合性是程序结构中各个模块之间相互关联的度量.它取决于各个模块之间的接口的复杂程度,调用模块的方式一级哪些信息通过接口,一般模块之间可能的连接方式有七种,耦合性由低到高分别是:非直接耦合,数据耦合,标记耦合,控制耦合,外部耦合,公共耦合,内容耦合.一个软件是由多个子程序组装而成,而一个程序由多个模块(方法)构成.耦合是指各个外部程序(子程序)之间的关系紧密度而内聚就是指程序内的各个模块之间的关系紧密度所以说,为什么要高内聚,模块之间的关系越紧密,出错就越少!低耦合就是说,子程序之间的关系越复杂,就会产生出更多的意想不到的错误!会给以后的维护工作带来很多麻烦一个优秀软件开发人员的必修课:高内聚高内聚Java 软件工程软件模式一个重要的模式:高内聚。
2. 高内聚(High Cohesion)高内聚是另一个普遍用来评判软件设计质量的标准。
内聚,更为专业的说法叫功能内聚,是对软件系统中元素职责相关性和集中度的度量。
如果元素具有高度相关的职责,除了这些职责内的任务,没有其它过多的工作,那么该元素就具有高内聚性,反之则为低内聚性。
高内聚要求软件系统中的各个元素具有较高的协作性,因为在我们在完成软件需求中的一个功能,可能需要做各种事情,但是具有高内聚性的一个元素,只完成它职责内的事情,而把那些不在它职责内的事情拿去请求别人来完成。
这就好像,如果我是一个项目经理,我的职责是监控和协调我的项目各个阶段的工作。
当我的项目进入需求分析阶段,我会请求需求分析员来完成;当我的项目进入开发阶段,我会请求软件开发人员来完成;当我的项目需要测试的时候,我会请求测试人员。
如果我参与了开发,我就不是一个高内聚的元素,因为开发不是我的职责。
我们的项目为什么要高内聚呢?我觉得可以从可读性、复用性、可维护性和易变更性四个方面来理解。
1.可读性一个人写文章、讲事情,条理清晰才能易于理解,这同样发生在读写软件代码上。
如果一堆代码写得一团乱麻,东一个跳转西一个调用,读它的人会感觉非常头疼。
这种事情也许一直在写程序的你我都曾经有过经历。
如果一段程序条理非常清晰,每个类通过名称或说明都能清楚明白它的意义,类的每个属性、函数也都是易于理解的它所应当完成的任务和行为,这段程序的可读性必然提高。
在软件产业越来越密集,软件产业中开发人员协作越来越紧密、分工越来越细的今天,软件可读性的要求相信也越来越为人们所重视。
2.复用性在软件开发中,最低等级的复用是代码拷贝,然后是函数的复用、对象的复用、组件的复用。
软件开发中最懒的人是最聪明的人,他们总是想到复用。
在代码编写的时候突然发现某个功能是曾经实现过的功能,直接把它拷贝过来就ok了。
如果这段代码在同一个对象中,那么就提出来写一个函数到处调用就行了。
如果不是在同一个对象中呢,就将其抽象成一个对象到处调用吧。
如果不在一个项目中呢,那就做成组件给各个项目引用吧。
代码复用也使我们的代码在复用的过程中不断精化、不断健壮、提高代码质量。
代码的复用的确给我们的开发带来了不少便利,但是一段代码能否在各个需要的地方都能复用呢?这给我们的软件开发质量提出了新的要求:好的代码可以复用,不好的则不行。
软件中的一个对象如果能保证能完成自己职能范围内的各项任务,同时又不去理会与自己职能无关的其它任务,那么它就能够保证功能的相对独立性,也就可以脱离自己所处的环境而复用到其它环境中,这是一个具有内聚性的对象。
3.可维护性和易变更性在前面《如何在struts+spring+hibernate的框架下构建低耦合高内聚的软件》中我提到,我们现在的软件是在不断变更的,这种变更不仅来自于我们的客户,更来自于我们的市场。
如果我们的软件通过变更能及时适应我们的市场需求,我们就可以在市场竞争中获胜。
如何能及时变更以适应我们的市场呢,就是通过调整软件的结构,使我们每次的变更付出的代价最小,耗费的人力最小,这种变更才最快最经济。
高内聚的软件,每个系统、模块、类的任务都高度相关,就使每一次的变更涉及的范围缩小到最小。
比如评审表发生了变更,只会与评审表对象有关,我们不会去更改其它的对象。
如果我们能做到这一点,我们的系统当然是可维护性好、易变更性好的系统。
那么,我们如何做到高内聚呢?就拿前面我提到的评审项目举例。
我现在要为“评审表”对象编写一段填写并保存评审表的代码。
评审表对象的职责是更新和查询评审表的数据,但是在显示一个要填写的评审表的时候,我需要显示该评审计划的名称、该评审计划有哪些评审对象需要评审。
现在我如何编写显示一个要填写的评审表的代码?我在评审表对象的这个相应的函数中编写一段查询评审计划和评审对象的代码吗?假如你这样做了,你的代码就不是高内聚的,因为查询评审计划和评审对象的数据不是它的职责。
正确的方法应当去请求“评审计划”对象和“评审对象”对象来完成这些工作,而“评审表”对象只是获取其结果。
另外,如果一个对象要完成一个虽然在自己职责范围内,但过程非常复杂的任务时,也应当将该任务分解成数个功能相对独立的子函数来完成。
我曾经看见一个朋友写的数百行的一个函数,让人读起来非常费劲。
同时这样的函数中一些相对独立的代码,本可以复用到其它代码中,也变成了不可能。
所以我给大家的建议是,不要写太长的函数,超过一百行就可以考虑将一些功能分解出去。
与“低耦合”一样,高内聚也不是一个绝对,而是一个相对的指标,应当适当而不能过度。
正如我们在现实生活中,如果在一个十来人的小公司,每个人的分工可能会粗一些,所分配的职责会广一些杂一些,因为其总体的任务少;而如果在一个一两百人的大公司,每个人的分工会细一些,所分配的任务会更加专一些,因为总体任务多,更需要专业化的分工来提高效率。
软件开发也是一样,如果“评审计划”对象完成的业务功能少,并且不复杂,它完全可以代理它的子表“评审对象”和“评审者”的管理。
但是“评审计划”对象需要完成的“对评审计划表的管理”这个基本职责包含的业务功能繁多或者复杂,它就应当将“对评审对象表的管理”交给“评审对象”对象,将“对评审者表的管理”交给“评审者”对象。
同样,高内聚的可维护性好、易变更性好只能是一个相对的指标。
如果一个变更的确是大范围的变更,你永远不可能通过内聚就不进行大范围的变更了。
同时内聚也是要付出代价的,所以你也不必要去为了一个不太可能的变更去进行过度设计,应当掌握一个度。
过度的内聚必将增加系统中元素之间的依赖,提高耦合度。
所以“高内聚”与“低耦合”是矛盾的,必须权衡利弊,综合地去处理。
在李洋等人翻译的《UML和模式应用》中,将内聚和耦合翻译为软件工程中的阴与阳,是中国人对内聚和耦合的最佳解释。
综上所述,“高内聚”给软件项目带来的优点是:可读性强、易维护和变更、支持低耦合、移植和重用性强。
一个优秀软件开发人员的必修课:GRASP(2)低耦合关键字: 设计模式我偶然在google或yahoo这样的搜索引擎搜索GRASP发现,除了国外的网站,国内网站多介绍和讨论GoF而很少介绍GRASP,即使这少量的文章也讲解非常粗略。
个人认为作为优秀的开发人员,理解GRASP比GoF更重要,故写此文章。
前面我在《(原创)一个优秀软件开发人员的必修课:GRASP软件开发模式浅析》中介绍了使用GRASP的目的,今天允许我调换一下顺序,先从低耦合讲起,因为诸如创建者模式、信息专家模式的根本目的就是降低耦合。
1. 低耦合(Low Coupling)“低耦合”这个词相信大家已经耳熟能详,我们在看spring的书籍、MVC的数据、设计模式的书籍,无处不提到“低耦合、高内聚”,它已经成为软件设计质量的标准之一。
那么什么是低耦合?耦合就是对某元素与其它元素之间的连接、感知和依赖的量度。
这里所说的元素,即可以是功能、对象(类),也可以指系统、子系统、模块。
假如一个元素A去连接元素B,或者通过自己的方法可以感知B,或者当B不存在的时候就不能正常工作,那么就说元素A与元素B耦合。
耦合带来的问题是,当元素B发生变更或不存在时,都将影响元素A的正常工作,影响系统的可维护性和易变更性。
同时元素A只能工作于元素B存在的环境中,这也降低了元素A的可复用性。
正因为耦合的种种弊端,我们在软件设计的时候努力追求“低耦合”。
低耦合就是要求在我们的软件系统中,某元素不要过度依赖于其它元素。
请注意这里的“过度”二字。
系统中低耦合不能过度,比如说我们设计一个类可以不与JDK 耦合,这可能吗?除非你不是设计的Java程序。
再比如我设计了一个类,它不与我的系统中的任何类发生耦合。
如果有这样一个类,那么它必然是低内聚(关于内聚的问题我随后讨论)。