低耦合高内聚各例子
【篇一:低耦合,高内聚各例子】
引用8楼sp1234的回复:接口,再设计上跟类型是同样的东西,就是类型。在设计上并不纠结什么编程术语,而是各种oo语言都公认的基本术语。
所以“写接口、写父类、写抽象类”,以及一大堆其它说法(比如说根本不支持的多重继承技术),都是一样的东西——可以用来降低耦合、保证高内聚地封装。
比如说你开发一个通用的atm程序,面对5种大类、25种小类,假设有500种不同的银行卡处理流程,你要写500个程序吗?不是的。你首先写了一个atm流程父类,然后5种大类的差别在子类中重写,然后25种小类与其大类的差别又分别在小类中进行重写,然后每一种银行卡的一点点差别又分别在每一个银行卡类中进行重写。
假设有1000个人跟这500种银行卡发生关系,是要考虑50万种情况吗?不是的。因为atm只有一种——所有的银行卡都是它的子类,因此具体的银行卡流程是通过父类给外界打交道的。
分层扩展,继承和多态,就是保证搞内聚低耦合的一种设计手段。
如果仅仅纠结“搞内聚、低耦合”的名词儿概念,实际上是文不对题的。只有理解了你说的“大型项目、要设计接口”的本质,才能真正把概念之间的联系说清楚!!
引用9楼sp1234的回复:你的同学显然是学习了工程概念,而你只是道听途说某个词儿跟某个词儿“相关”然后喜欢拿出来说一说。这次就可以超越标题党而理解一些“接口、继承、抽象”的实质。
实际上这是很简单的道理。但是要知道,许多道理被一些莫名其妙的“概念解释”给污染了。当一个人研究know-how的时候,如果他满脑子只有know-what,他就容易变成一个标题党。
所以技术并没有什么事非,完全是根据不同的场景进行深入细致的“理解”。不能永远都是背字典、扣字眼。而是要对所有的概念,都能根据当时的研究的场景,深入到不同的细节。学习
【篇二:低耦合,高内聚各例子】
“低耦合”这个词相信大家已经耳熟能详,我们在看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还是sqlserver,如何执行的操作,与我无关。
但是,作为优秀的开发人员,仅仅依靠框架提供的降低软件耦合的方法是远远不够的。根据我的经验,以下一些问题我们应当引起注意:
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的框架下构建低耦合高内聚的软件结构》一文。
总之,“低耦合”给软件项目带来的优点是:易于变更、易于重用。
2.高内聚(highcohesion)
高内聚是另一个普遍用来评判软件设计质量的标准。内聚,更为专业的说法叫功能内聚,是对软件系统中元素职责相关性和集中度的度量。如果元素具有高度相关的职责,除了这些职责内的任务,没有其它过多的工作,那么该元素就具有高内聚性,反之则为低内聚性。高内
聚要求软件系统中的各个元素具有较高的协作性,因为在我们在完成软件需求中的一个功能,可能需要做各种事情,但是具有高内聚性的一个元素,只完成它职责内的事情,而把那些不在它职责内的事情拿去请求别人来完成。这就好像,如果我是一个项目经理,我的职责是监控和协调我的项目各个阶段的工作。当我的项目进入需求分析阶段,我会请求需求分析员来完成;当我的项目进入开发阶段,我会请求软件开发人员来完成;当我的项目需要测试的时候,我会请求测试人员。。。。。。如果我参与了开发,我就不是一个高内聚的元素,因为开发不是我的职责。我们的项目为什么要高内聚呢?我觉得可以从可读性、复用性、可维护性和易变更性四个方面来理解。
1.可读性
一个人写文章、讲事情,条理清晰才能易于理解,这同样发生在读写软件代码上。如果一堆代码写得一团乱麻,东一个跳转西一个调用,读它的人会感觉非常头疼。这种事情也许一直在写程序的你我都曾经有过经历。如果一段程序条理非常清晰,每个类通过名称或说明都能清楚明白它的意义,类的每个属性、函数也都是易于理解的它所应当完成的任务和行为,这段程序的可读性必然提高。在软件产业越来越密集,软件产业中开发人员协作越来越紧密、分工越来越细的今天,软件可读性的要求相信也越来越为人们所重视。
ajax实例 文件浏览2.复用性
在软件开发中,最低等级的复用是代码拷贝,然后是函数的复用、对象的复用、组件的复用。软件开发中最懒的人是最聪明的人,他们总是想到复用。在代码编写的时候突然发现某个功能是曾经实现过的功能,直接把它拷贝过来就ok了。如果这段代码在同一个对象中,那么就提出来写一个函数到处调用就行了。如果不是在同一个对象中呢,就将其抽象成一个对象到处调用吧。如果不在一个项目中呢,那就做成组件给各个项目引用吧。代码复用也使我们的代码在复用的过程中不断精化、不断健壮、提高代码质量。代码的复用的确给我们的开发带来了不少便利,但是一段代码能否在各个需要的地方都能复用呢?这给我们的软件开发质量提出了新的要求:好的代码可以复用,不好的则不行。软件中的一个对象如果能保证能完成自己职能范围内的各项任务,同时又不去理会与自己职能无关的其它任务,那么它就能够保证功能的相对独立性,也就可以脱离自己所处的环境而复用到其它环境中,这是一个具有内聚性的对象。
3.可维护性和易变更性
在前面《如何在struts spring hibernate的框架下构建低耦合高内聚的软件》中我提到,我
们现在的软件是在不断变更的,这种变更不仅来自于我们的客户,更来自于我们的市场。如果我们的软件通过变更能及时适应我们的市场需求,我们就可以在市场竞争中获胜。如何能及时变更以适应我们的市场呢,就是通过调整软件的结构,使我们每次的变更付出的代价最小,耗费的人力最小,这种变更才最快最经济。高内聚的软件,每个系统、模块、类的任务都高度相关,就使每一次的变更涉及的范围缩小到最小。比如评审表发生了变更,只会与评审表对象有关,我们不会去更改其它的对象。如果我们能做到这一点,我们的系统当然是可维护性好、易变更性好的系统。