软件设计强内聚性_第1页
软件设计强内聚性_第2页
软件设计强内聚性_第3页
软件设计强内聚性_第4页
全文预览已结束

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

强内聚性内聚性指的是在一个子程序中,各种操作之间互相联系的紧密程度。有些程序员喜欢用“强度”一词来代替内聚性,在一个子程序中各种操作之间的联系程度有多强?一个诸如Sin()之类的函数内聚性是很强的,因为整个子程序所从事的工作都是围绕一个函数的。而像SinAndTan()的内聚程度就要低得多了,因为子程序中所进行的是一项以上的工作。强调强相关性的目的是,每一个子程序只需作好一项工作,而不必过分考虑其它任务。这样作的好处是可以提高可靠性。通过对450个Fortran子程序的调查表明,50%的强内聚性子程序是没有错误的,而只有18%的弱内聚性子程序才是无错的(Card,Carch和Agresti1986)。另一项对另外450个子程序的调查则表明,弱内聚性子程序的出错机会要比强内聚性出错机会高6倍,而修正成本则要高19倍(Selby和Basili1991)。关于内聚性的讨论一般是指几个层次。理解概念要比单纯记住名词重要得多。可以利用这些概念来生成内聚性尽可能强的子程序。5.3.1可取的内聚性内聚性的想法是由WayneStevens,GlenfordMyers和LarryConstantine等人在1974年发表的一篇论文中提出来的,从那以后,这个想法的某些部分又逐渐得到了完善。以下是一些通常认为是可以接受的一些内聚类型:功能内聚性。功能内聚性是最强也是最好的一种内聚,当程序执行一项并且仅仅是一项工作时,就是这种内聚性,这种内聚性的例子有:sin(),GetCustomerName(),EraseFile(),CaldoanPayment()和GetIconlocation()等等。当然,这个评价只有在子程序的名称与其实际内容相符时才成立。如果它们同时还作其它工作,那么它们的内聚性就要低得多而且命名也不恰当。⑵顺序内聚性。顺序内聚性是指在子程序内包含需要按特定顺序进行的、逐步分享数据而又不形成一个完整功能的操作,假设一个子程序包括五个操作:打开文件、读文件、进行两个计算、输出结果、关闭文件。如果这些操作是由两个子程序完成的,DoStep1()打开文件、读文件和计算操作,而DoStep2()则进行输出结果和关闭文件操作。这两个子程序都具有顺序内聚性。因为用这种方式把操作分隔开来,并没有产生出独立的功能。但是,如果用一个叫作GetFileData()的子程序进行打开文件和读文件的操作,那么这个子程序将具有功能内聚性。当操作来完成一项功能时,它们就可以形成一个具有功能内聚性的子程序。实际上,如果能用一个很典型的动宾词组来命名一个子程序,那么它往往是功能内聚性,而不是顺序内聚性。给一个顺序内聚性的子程序命名是非常困难的,于是便产生了像Dostep1()这种模棱两可的名字。这往往意味着你需要重新组织和设计子程序,以使它是功能内聚性的。通讯内聚性。通讯内聚性是在一个子程序中,两个操作只是使用相同数据,而不存在其它任何联系时产生的。比如,在GetNameAndChangePhoneNumber()这个子程序中,如果Name和PhoneNumber是放在同一个用户记录中的,那么这个子程序就是通讯内聚性。这个子程序从事的是两项而不是一项工作,因此,它不具备功能内聚性。Name和PhoneNamber都存储在用户记录中,不必按照某一特定顺序来读取它们,所以,它也不具备顺序内聚性。这个意义上的内聚性还是可以接受的。在实际中,一个系统可能需要在读取一个名字的同时变更电话号码。一个含有这类子程序的系统可能有些显得别扭,但仍然很清楚且维护性也不算差,当然从美学角度来说,它与那些只作一项工作的子程序还有一定差距。临时内聚性。因为同时执行的原因才被放入同一个子程序里,这时产生临时内聚性。典型的例子有;Startup。,CompleteNewEmployee(),Shutdown()等等,有些程序员认为临时内聚性是不可接受的,因为它们有时与拙劣的编程联系在一切,比如,在像Startup。这类子程序中往往含有东拼西凑的杂烩般的代码。要避免这个问题,可以把临时内聚性子程序设计成一系列工作的组织者。前述的Startup()子程序进行的操作可能包括:读取一个配置文件、初始化一个临时文件、建立内存管理、显示初始化屏幕。要想使它最有效地完成这些任务,可以让这个子程序去调用其它的专门功能的子程序,而不是由它自己直接来完成这些任务。5.3.2不可取的内聚性其余类型的内聚性,一般来说都是不可取的。其后果往往是产生一些组织混乱而又难以调试和改进的代码。如果一个子程序具有不良的内聚性,那最好重新创建一个较好的子程序,而不要去试图修补它。知道应该避免什么是非常重要的,以下就是一些不可取的内聚性:过程内聚性。当子程序中的操作是按某一特定顺序进行的,就是过程内聚性。与顺序内聚性不同,过程内聚性中的顺序操作使用的并不是相同数据。比如,如果用户想按一定的顺序打印报告,而所拥有的子程序是用于打印销售收入、开支、雇员电话表的。那给这个子程序命名是非常困难的,而模棱两可的名字往往代表着某种警告。逻辑内聚性。当一个子程序中同时含有几个操作,而其中一个操作又被传进来的控制标志所选择时,就产生了逻辑内聚性。之所以称之为逻辑内聚性,是因为这些操作仅仅是因为控制流,或者说“逻辑”的原因才联系到一起的,它们都被包括在一个很大的if或者case语句中,它们之间并没有任何其它逻辑上的联系。举例来说,一个叫作InputAll()的子程序,程序的输入内容可能是用户名字、雇员时间卡信息或者库存数据,至于到底是其中的哪一个,则由传入子程序的控制标志决定。其余类似的子程序还有ComputeAll(),EditAll(),PrintAll()等等。这类子程序的主要问题是一定要通过传入一个控制标志来决定子程序处理的内容。解决的办法是编写三个不同的子程序,每个子程序只进行其中一个操作。如果这三个子程序中含有公共代码段,那么还应把这段代码放入一个较低层次的子程序中,以供三个子程序调用。并且,把这三个子程序放入一个模块中。但是,如果一个逻辑内聚性的子程序代码都是一系列if和case语句,并且调用其它子程序,那么这是允许的。在这种情况下,如果程序的唯一功能是调度命令,而它本身并不进行任何处理,那么这可以说是一个不错的设计。对这种子程序的专业叫法是“事物处理中心”,事物处理中心往往被用作基础环境下的事件处理,比如,AppleMacintosh和MicrosoftWindows。偶然内聚性。当同一个子程序中的操作之间无任何联系时,为偶然内聚性。也叫作“无内聚性”。本章开始时所举的Pascal例程,就是偶然内聚性。以上这些名称并不重要,要学会其中的思想而不是这些名词。写出功能内聚性的子程序几乎总是可能的,因此,只要重视功能内聚性以获取最大的好处就可以了。5.3.3内聚性举例以下是几个内聚性的例子,其中既有好的,也有坏的:功能内聚性例子。比如计算雇员年龄并给出生日的子程序就是功能内聚性的,因为它只完成一项工作,而且完成得很好。顺序内聚性的例子。假设有一个按给出的生日计算雇员年龄、退休时间的子程序,如果它是利用所计算的年龄来确定雇员将要退休的时间,那么它就具有顺序内聚性。而如果它是分别计算年龄和退休时间的,但使用相同生日数据,那它就只具有通讯内聚性。确定程序存在哪种不良内聚性,还不如确定如何把它设计得更好重要。怎样使这个子程序成为功能内聚性呢?可以分别建立两个子程序,一个根据生日计算年龄,另外一个根据生日确定退休时间,确定退休时间子程序将调用计算年龄的程序,这样,它们就都是功能内聚性的,而且,其它子程序也可以调用其中任一个子程序,或这两个部调用。通讯内聚性的例子。比如有一个打印总结报告,并在完成后重新初始化传进来的总结数据的子程序,这个子程序具有通信内聚性,因为这两个操作仅仅是由于它们使用了相同的数据才联系在一起。同前例一样,我们考虑的重点还是如何把它变成是功能内聚性,总结数据应该在产生它的地方附近被重新初始化,而不应该在打印子程序中重新初始化。把这个子程序分为两个独立的子程序.第一个打印报告,第二个则在产生或者改动数据的代码附近重新初始化数据。然后,利用一个较高层次的子程序来代替原来具有通讯相关的子程序,这个子程序将调用前面两个分出来的子程序。逻辑内聚性的例子。一个子程序将打印季度开支报告、月份开支报告和日开支报告.具体打印哪一个,将由传入的控制标志决定,这个子程序具有逻辑内聚性,因为它的内部逻辑是由输进去的外部控制标志决定的。显然,这个子程序不是按只完成一项工作并把它作好的原则。怎样使这个子程序变为功能内聚性呢?建立三个子程序:一个打印季度报告,一个打印月报告、一个打印日报告,改进原来的子程序,让它根据传送去控制标志来调用这三个子程序之一。调用子程序将只有调用代码而没有自己的计算代码,因而具有功能内聚性。而三个被调用的子程序也显然是功能内聚性的。非常巧合,这个只负责调用其它子程序的子程序也是一个事务处理中心。最好用如DispatchReportPrinting()之类带有“调度”或“控制”等字眼的词来给事务处理中心命名,以表示它只负责命令的调度,而本身并不做任何工作。逻辑内聚性的另一个例子。考虑一个负责打印开支报表、输入新雇员名字并备份数据库的子程序,其具体执行内容将由传入的控制标志控制。这个子程序只具有逻辑内聚性,虽然这个关联看起来是不合逻辑的。要想使它成为功能内聚性,只要按功能把它分成几部分就可以了。不过,这些操作有些过于凌乱。因此,最好重新建立一个调用各子程序的代码。当拥有几个需要调用的子程序时,重新组织调用代码是比较容易的。过程内聚性的例子。假设有一个子程序,它产生读取雇员的名字,然后是地址,最后是它的电话号码。这种顺序之所以重要,仅仅是因为它符合用户的需求,用户希望按这种顺序进行屏幕输入。另外一个子程序将读取关于雇员的其它信息。这个子程序是过程内聚性,因为是由一个特定顺序而不是其它任何原因,把这些操作组合在一起的。与以前一样,如何把它变为功能内聚性的答案仍然是把它分为几个部分,并把这几部分分别放入程序中。要保证调用子程序的功能是单一、完善的。调用子程序应该是诸如GetEmployeeData()这样的子程序,而不该是像GetFirstPartofEmployeeData()这类的子程序。可能还要改动其余读取数据的子程序。为得到功能内聚性,改动几个子程序是很正常的。同时具有功能和临时内聚性的程序。考虑一个具有完成一项事物处理所有过程的子程序,从用户那里读取确认信息,向数据存入一个记录,清除数据域,并给计数器加1。这个程序是功能内聚性的,因为它只从事一项工作,进行事物处理,但是,更确切地说,这个子程序同时也是临时内聚性的,不过当-个子程序具有两种以上内聚性时,一般只考虑最强的内聚性。这个例子提出了如何用一个名字恰如其分地抽象描述出程序内容的问题。比如可以称这个子程序为ConfirmEntryAndAdjustData(),表示这个干程序仅具有偶然内聚性。而如果称它为CompleteTransaction(),那么就可能清楚地表示出这个子程序仅具有一个功能,而已具有功能内聚性。过程性、临时或者可能的逻辑内聚性。比如一个进行某种复杂计算前5个操作,并把中间结果返回到调用子程序。由于5项操作可能要用好几个小时,因此当系统瘫痪时,这个子程序将把中间结果存入一个文件中,然后,这个子程序检查磁盘,以确定其是否有足够空间来存储最后计算结果,并把磁盘状态和中间结果返回到调用程序。这个子程序很可能是过程内聚性的,但你也可能认为它具有临时内聚性,甚至具有逻辑内聚性。不过,不要忘了问题的关键不是争论它具有哪种不好的内聚性,而是如何改善其内聚性。原来的子程序是由一系列令人莫名其妙的操作组成的,与功能内聚性相距甚远,首先,调用子程序不应该调用一个,而应该调用几个独立的子程序:1)进行前5步计算的子程序;2)把中间结果存入一个文件;3)确定可用的磁盘存储空间。如果调用子程序被称作ComputeExtra

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论