通常认为,一个易于维护的系统,就是复用率较高的系统;而一个复用性较好的系统,就是一个易于维护的系统。但是实际上,可维护性和可复用性是两个独立的目标,就像两只奔跑的兔子一样,并不总是方向一致的。
对于面向对象的软件系统设计来说,在支持可维护性的同时,提高系统的可复用性是一个核心的问题。
一、软件系统的可维护性
软件开发是一个比较快速的过程,一般只需要半年时间。但是系统的维护却是一个长期的过程,需要很多年。并且在一个软件项目的周期内,花费在维护上面的钱,是花费在原始开发上面的钱的两倍。
作为一个开发人员必须要认识到,软件的维护就是软件的再生。一个好的软件设计,必须能够允许新的设计要求以较为容易和平稳的方式加入到已有的系统中去,从而使这个系统能够不断的焕发青春。 一个可维护性较好的系统,应当允许维护工作能够以容易、准确、安全和经济的形式进行。
1、一个典型的软件生命周期
一个软件项目开始了,系统设计师拿到了系统的设计要求,设计师就会开始系统设计;这个系统毫无疑问将是一个优美的系统。系统的美,首先存在于设计师的头脑中,然后存在于设计图纸上,然后变成一个原型系统,最后变成一个真实的、有血有肉、可以交付客户使用的产品。
设计师喜欢看着他运行,程序员喜欢它的每一个功能键和图形视窗,而客户终于看到花出去的钱变成了实现。这个时候,这个系统就像一个美少女一样,毫无疑问是纯净的、优美的、动人心弦的。
但是不久事情就开始发生变化。客户看了运行的系统,又提出了一些“小小的”修改要求,这些要求都是客户在提出系统设计要求的时候遗忘的一些“小”问题。设计师讨论之后,给出了一些设计上面的修改。由于这些修改于现有系统的设计并不一定相容,所以设计师不得不采取一些权宜之计,是的这些修改看上去就像一个美丽少女脸上的青春痘。但是好像所有的软件都不能避免这些“青春痘”似的东西的出现,所以一切还不是很糟。
可是事情并没有就此结束,这些小的痘痘越来越多,而且其中有一些变成了系统的肿瘤。随着时间的流逝,这些肿瘤变成了系统中最主要的组成部分,当初的美少女变成了一个丑陋不堪,日渐“腐烂”的代码,以至于没有人愿意去维护他。人们把它叫做遗留系统,而不得不去维护这个遗留系统的人们,会天天诅咒设计这个系统的设计师:是谁设计出这么丑陋的一个东西??!!
经过一段漫长的时间后,“苦难”终于要结束了!在抱怨了软件系统的维护之昂贵之后,客户决定投入一笔资金,一个新的系统将被设计出来,而这个新系统将具有这个正在死去的系统的所有功能(当然还包括一些新的功能),并且取代这个已经“腐烂”的系统。
但是仔细想想,这个新系统会面临怎样的命运呢?也许这仅仅是下一个轮回的开始。
2、导致这种情况的真正原因
导致一个软件设计的可维护性较低,也就是说会随着性能要求的变化而“腐烂”的真正原因有四个:过于僵硬、过于脆弱、复用率低、黏度过高。
①过于僵硬:很难在一个软件系统里加入一个新的性能,哪怕是很小的都很难。这是因为加入一个新新能,不仅仅意味建造一个独立的新模块,而且因为这个新性能会波及很多其他模块,最后变成跨越几个模块的改动。使得一个起初只需要几天的工作,最后变成持续好久的作战。由于这种设计上的缺陷,使得项目经理不敢轻易向系统加入新功能。这就造成一个软件系统一旦做好,就不能增加新功能的僵化情况。
②过于脆弱:与软件过于僵硬同时存在的,是软件系统在修改已有代码时过于脆弱。对一个地方的修改,往往会导致看上去没有什么关系的另一个地方发生故障。尽管在修改之前,设计师们会竭尽所能预测可能的故障地点,地那是在修改完成之前,系统的原始设计师们甚至都无法确切预测到可能会波及到的地方。这种一碰就碎的情况,造成软件系统过于脆弱。
③复用率低:所谓复用,就是指一个软件的组成部分,可以在同一个项目的不同地方甚至另一个项目中重复使用。每当程序员发现一段代码,函数,模块所做的事情是可以在新的模块、或者新系统中使用的时候,他们总会发现,这些已有的代码依赖于一大堆其他的东西,以至于很难将他们分开。最后,他们发现最好的办法就是不去“碰”这些已有的东西,而是重新写自己的代码。他们可能会使用源代码黏贴的办法,以最原始的复用方式,节省一些时间。这样的系统就有复用率低的问题。
④黏度过高:有的时候,一个改动可以保持原始的设计意图和原始设计框架的方式进行,也可以破坏原始意图和框架的方式进行。第一种办法无疑会对系统的未来有利,第二种办法是权宜之计,可以解决短期问题,但是会牺牲中长期的利益。
如果第二种办法比第一种办法容易很多的话,程序员就有可能牺牲中长期的利益,采取权宜之计:在模块中搭建一个短路桥,或者在一个通用的逻辑中制造一个特例,以便解决眼前的需要。
一个系统设计,如果总是使得第二种办法比第一种办法容易,就叫做年度过高。一个黏度过高的系统会诱使维护它的程序员采取错误的维护方案,并惩罚采取正确维护方案的程序员。
3、设计的目标
一个好的系统设计应该有如下的性质:可扩展性、灵活性、可插入性。这三条性质就是一个系统设计应当达到的目标。
①可扩展性:新的性能可以很容易的加入到系统中去,就是可扩展性。这就是系统“过于僵硬”的属性的反面。可扩展性要求一个新系统的加入,应该不会影响原有的功能,如果不是,则这个系统就不是扩展型很好的系统。
②灵活性:可以允许代码修改平稳的发生,而不会波及到很多其他的模块,这就是灵活性。比如一辆汽车的空调发生了故障,技师修理了空调。如果空调修好之后,发现系统的发动机不能启动了,这就不是一个灵活的系统。
③可插入性:很容易的讲一个类抽出去,同时将另一个有同样接口的类加入进来,这就是可插入性。比如应该可以很容易的将一辆汽车的防撞气囊取出来,换上一个新的。如果气囊拿出来后,汽车的传动杆不工作了,那么这个系统就不是一个可插入性很好的系统。
那么,怎样才能做出一个符合这三项要求的设计呢?关键是恰当的提高软件的可维护性和可复用性。
二、系统的可复用性
1、复用的重要性
软件的复用的好处有:①较高的生产效率;②较高的软件质量;③恰当使用复用可以改善系统的可维护性。更重要的是,复用与系统的可维护性有直接的关系。
2、传统的复用
在传统的理解中,复用有一下几种方式:①代码的黏贴复用;②算法的复用;③数据结构的复用;
3、可维护性与复用的关系
传统的复用方案的一个致命缺陷就是复用常常是以破坏可维护性为代价的。比如两个模块A和B同事使用另一个模块C中的功能。那么当A需要C增加一个新的行为的时候,B有可能不需要、甚至不允许C增加这个新行为。如果坚持使用复用,就不得不以系统的可维护性为代价;而如果从保持系统的可维护性出发,就只好放弃复用。可维护性与可复用性是有共同性的两个独立特性,他们就像是两只同时在奔跑的兔子,方向并不能一直保持一致。
因此,一个重要的概念就是支持可维护性的复用,也就是在保持甚至提高系统的可维护性的同时,实现系统的复用。
4、面向对象设计的复用
在面向对象的语言中,数据的抽象化、继承、封装和多态性是几项最重要的语言特性,这些特性使得一个系统可以在更高的层次上提供可复用性。数据的抽象化和继承关系使得概念和定义可以复用;多态性使得实现和应用可以复用;而抽象化和封装可以保持和催进系统的可维护性。这样一来,复用的焦点不再集中在函数和算法等具体实现细节上,而是集中在最重要的含有宏观商业逻辑的抽象层次上。换言之,复用的焦点发生了“倒转”。
发生复用焦点的倒转并不是因为实现细节的复用不再重要,而是因为这些细节上的复用往往已经做得很好,而且抽象层次是比这些细节更值得强调的复用焦点,因为它们是在提供复用性的同时保持和提高可维护性的关键。
既然抽象层次是一个应用系统做战略性判断和决定的地方,那么抽象层次就应当是较为稳定的,应当是复用的重点。如果抽象层次的模块相对独立于具体层次的模块的话,那么具体层次内部的变化就不会影响到抽象层次的结构,所以抽象层次的模块的复用就会较为容易。
5、对可维护性的支持
首先,恰当的提高系统的可复用性,可以提高系统的可扩展性。允许一个具有同样接口的新的类替代旧的类,是对抽象接口的复用。客户端依赖于一个抽象的接口,而不是一个具体实现类,使得这个具体类可以被另一个具体类所取代,而不影响到客户端。 系统的可扩展性是有“开-闭”原则,里氏代换原则、依赖倒转原则和组合/聚合复用原则所保证的。
其次,恰当的提高系统的可复用性,可以提高系统的灵活性。在一个设计得当的系统中,每一个模块都相对于其他模块独立存在,并只保持与其他模块的尽可能少的通信。这样一来,在其中某一个模块发生代码修改的时候,这个修改的压力不会传递到其他的模块。系统的灵活性是由“开-闭”原则、迪米特法则、接口隔离原则做保证的。
最后,恰当的提高系统的可复用性,可以提高系统的可插入性。在一个符合“开-闭”原则的系统中,抽象层封装了与商业逻辑有关的重要行为,这些行为的具体实现有实现层给出。当一个实现类不再满足需要,需要以另一个实现类取代的时候,系统的设计可以保证旧的类可以被“拔出”,新的类可以被“插入”。系统的可插入性是有“开-闭”原则、里氏代换原则,组合/聚合复用原则以及依赖倒转原则保证的。
这就是说,通过设计原则的灵活运用,是可以提高一个系统的可维护性同时,提高系统的可复用性的。灵活的使用设计原则进行系统设计,就可以抓到这两只同时在奔跑的兔子。
参照:《java与模式》
相关推荐
在软件开发领域,可维护性和可复用性是衡量软件质量的重要指标,它们直接关系到软件的生命周期成本和效率。本文将深入探讨这两个概念以及如何通过设计模式、框架和架构来提升它们。 首先,让我们来看看可维护性。可...
同时,复用可以改善产品质量,例如通过提供更好的互操作性和提高系统的可维护性。 在软件复用类型方面,我们可以讨论机会复用,这是一种在编程期间发现并利用机会进行复用的情况。例如,在编写代码时可能发现某些...
NATO的标准还包括了如何对软件构件进行可复用性评估的方法论,以确保只有高质量的构件才能被纳入复用体系。 **3. 构件库的设计与管理** 此外,NATO还提供了关于如何设计和管理高效可靠的构件库的具体指南,包括...
### 软件工程中的可维护性与可扩展性设计 #### 第1章 简介 **软件工程概述** 软件工程是一门工程学科,它通过系统化、规范化和量化的方法来开发和维护软件。软件工程的目标是提高软件产品的质量,确保其能够满足...
### 软件复用过程讲座报告 ...通过建立并遵循复用过程框架,企业可以系统化地管理其软件资产,确保复用活动的有效性和可持续性。此外,持续的过程度量与改进也是确保软件复用成功的关键因素之一。
2. 软件复用的优势:减少开发时间,降低开发成本,提高软件质量,增强软件的可维护性和可扩展性,同时也有助于提升开发者的技术水平和团队间的协同效率。 3. 软件复用的挑战:软件复用并非易事,需要解决兼容性、互...
**软件系统可维护性** - **可读性**:代码易于理解和修改。 - **可测试性**:软件容易进行测试,以便发现和修复错误。 - **可重用性**:软件组件可以在多个项目中重复使用。 - **可扩展性**:系统可以轻松地添加新...
### 软件工程与软件系统可维护性评估 #### 第1章 软件工程概述 ##### 软件工程概念 软件工程是一种将系统化、规范化、可度量化的方法应用于软件的开发、运行和维护的过程。其核心目标在于通过标准化的方法来降低...
通过软件构件技术,可以提高代码的可重用性、可维护性和可扩展性。 在未来,软件复用和软件构件技术将迎来新的发展机遇。云计算、人工智能等技术的不断发展,将为软件复用和软件构件技术提供更多的可能性。例如,...
### 软件工程与软件系统可维护性评估 #### 第1章 软件工程概述 **软件工程定义与历史** - **定义**: 软件工程是一门集成了系统化、规范化、可度量化的方法和技术来支持软件产品的开发、运行及维护的学科。 - **...
设计模式是软件工程中的一种重要概念,它代表了在特定情境下解决常见问题的最佳实践。...通过深入学习和实践这些设计模式,开发者可以提高代码的可读性、可维护性和可扩展性,从而提升软件工程的效率和质量。
框架是提高软件可复用性的重要工具。框架定义了一组标准的结构、接口和行为,供开发者使用和维护。使用框架可以减少软件开发的风险和成本,提高软件的可维护性和可扩展性。 2.1 MVC 框架 MVC是一种常见的Web应用...
构件复用不仅限于代码层面的复用,它更加关注于软件设计和架构层面,意在提高软件构建的效率和软件系统的可维护性、可扩展性。 构件复用的关键在于构件的独立性、可组合性和接口的标准化。独立性保证了构件可以在...
### 软件工程与软件系统可维护性评估 #### 第1章 软件工程概述 **软件工程定义与历史** - **定义**: 软件工程是一门集成了系统化、规范化以及可度量化的方法和技术来支持软件产品的开发、运行及维护的学科。 - **...
正确使用软件库能极大地提升开发效率,同时保持代码的整洁和可维护性。 设计模式是另一种实现软件复用的方法,它提供了在特定情境下解决常见问题的标准化解决方案。设计模式不是具体的代码,而是一种通用的语言,...
在复用过程中,需要建立有效的检索系统来查找合适的复用资源,同时还需要评估候选组件的质量、兼容性和可扩展性,以确保其能够在目标系统中顺利工作。 然后,我们关注“组织”。组织层面的软件复用是指企业或团队...