Software Construction——Lab3(关于软件可复用性、可维护性的实验)的总结

写在前面:

我们在之前lab2的实现中较为仔细的考虑了软件面向对象编程、抽象数据类型的特性,这一方面的内容是的我们在面对实际生活的具体需求的实现时有了相对大一学的C而言更为适用的编程实现思路。
但是,除了能够有初步的面向需求的对象的这种思路、实现出具有实际应用价值的软件之外,我们还需要考虑关乎软件质量的另外几项指标,其中就包括软件的可维护性和可复用性(也是我们在lab3中主要需要考虑的部分),这两点是在说什么呢?
可维护性是说,我们开发一个软件出来之后,大多数情况下不可能仍那就不管了,而是要不断的修整用户反馈的bug,随需求更改、增加软件功能的,也就是我们说的维护。这个过程需要我们对初版代码进行不断修改,具有好的可维护性的软件就是指我们在这个修改过程中应该能尽量少而轻松的改动代码而达成我们的目的,这就需要我们在最初进行软件的整体框架的设计乃至较底层的实现时多加考虑,而需要往哪些具体的方向考虑我们下面会提到。
那可复用性呢?设想这样一个场景:我们一个软件中的很多个类中都要用到某个功能基本相同的方法,而且有可能以后新加的类大概率也要用到这个方法,那我们是应该在每个类中都把这个方法实现一遍还是尽量只实现一遍而所有的ADT都用这一个方法呢?显然我们一般会选择后者,因为这可以大大的降低我们开发软件花费的成本,可复用性的大意就是这样,对于我们要用到的一个功能,我们尽量只实现一遍,在以后各类的实现中重复利用它,而非在每个类中都从头到尾实现一遍。

标题可复用性与可维护性的评价标准:

下俩我们分别通过对可复用性和可维护性最常用的的几条评价标准来深化对其的理解,了解一下设计出一个可复用性、可维护性较强的软件的大体方向是什么样的:
可维护性的评价标准:
1.设计结构是否简单?(尽量使用模块化编程,即将软件功能的实现拆分为独立的能够实现某一功能的模块,模块之间的依赖应尽量减小)
2.模块之间是否松散耦合、模块内部是否内聚度足够高?
3.是否存在大量的重复性代码(类似的功能是否重复实现了多次)?
4.是否在适合使用委托(delegation)的情况下使用了委托而非继承?
5.其他的代码风格方面,方法的实现、ADT的实现、参数列表是否“又臭又长”?(一个ADT应该尽量简洁,实现单一的功能)

随后是可复用性的一些参考标准:
1.开发的可复用模块是否足够简单易用、规模较小(如果别人想要使用你开发出的复用模块,是不是容易理解和应用,会不会因为你的模块用起来也就是适配过于复杂而导致开发成本不减反增)?
2.是否尽量使用了泛型和参数化的技术?(上一篇博客我们较为详细了探讨了关于泛型的知识,通过应用泛型使得模块被更多类型的变量使用,也是可复用性较强的表现)
3.是否和相应的标准兼容?
4.模块是否是灵活可变以适应变化的需求的?
5.模块稳定(靠谱)吗?(一个满是bug的模块谁敢用…)
6.是否有足够的帮助文档支持?(他人在应用你的可复用模块时需要了解这些模块各自的职能和使用方法,你需要写出合适的文档信息对这些加以说明)

现在我们对大体的方向已经有了初步的了解,下面就来看几个本次实验我应用到的一些设计思路与工程技术。(lab3的实验要求大家应该可以在CSDN上找到,由于篇幅较长这里就不赘述了,不过在后面每一部分都会提到必要的实验内容)

实验中用到的设计思想:

整体框架的设计:CRP原则
我们的这次的实验需要设计出三个任务项管理系统,它们大体是相似的,都是为了管理计划项。之所以是三个而不是一个,是为了让我们在完成实验的过程中尽可能考虑如何尽可能的将一个功能模块进行复用,从而只需要开发一遍而非三遍。我选择的分别是航班、列车以及课程计划项系统,每一种计划项有自己的个性化特点,但三者也均可以抽象出其共有的特点,比如每一种类型的计划项均有自己所在的位置(出发抵达机场、途经车站、上课的教室),都有自己的计划时间,都有所需要占用的特定资源(飞机、车厢组、教师)等等。根据上个实验,我们很轻松地想到把它们以某种方式实现为特定的ADT。
但问题来了,我们的计划项ADT该如何使用这些特定的ADT?(???我在问啥)我们通过举例来说一下这个问题在问啥:我们知道三种计划项均需要占用特定资源,但是占用资源的数量是不同的,比如我们的一个航班计划项仅需要占用一架飞机,课程计划项也是只需一位老师(这些需求是暂时的,以后可以改动)而一个列车计划项却需要若干个有序的车厢组合。那我们在实现特定的计划项ADT时想要利用这些特定资源,包括对资源对象的set、get等等功能,该怎么处理?在没学第四章和第五章之前可能我们会在每个计划项ADT中把这些方法全都实现一遍,这样做的结果就是,极大增加了开发成本,特别是软件规模增大以后,或者你要设计100个计划项系统,一个个去重复实现真的想都不敢想,这是从可复用性的角度考虑的,另外就算我们按这样实现了,以后维护软件的时候有需求发生变化,你要去100个系统中一个个找一个个改,那…
这就体现了可复用、可维护性强的软件的优点,我们用继承(inheritance)或者委托(delegation)的方法,将ADT的某一类特点设定为抽象类或接口并继承或委托,就不必在每个计划项ADT中分别实现了。现在就需要更进一步考虑,我们用继承还是委托?先来看下这张关于每一类计划项所具有的特征的表格:在这里插入图片描述
我们可以看到,对每个计划项而言需要组合不同特点的接口或类,如果我们单单使用继承的思想,对于多个特征而言会形成繁杂的继承树,比如我们的基类计划项先继承有关多个位置类,为了有多个时间对的特性,还需要实现继承这个类的类,产生组合爆炸的局面。这个大家可以想一下会变成什么样,我就不赘述了。
为此,我们还是利用组合委托的特性解决这个问题,每一类特点定义自己的接口,针对每类特点的不同特征取值,分别实现针对该类特点接口的不同集体类,并通过接口组合在计划项ADT上,将各类特点的具体实现组合在一起,形成满足满足上述要求的计划项ADT(包含了该应用内的全部特殊功能)。
并且,在每一个计划项ADT的具体实现中,对于每类特性的相关操作操作,比如说我们设置列车途经车站的set操作,通过委托的方式调用外部每个特点类接口中的各具体实现类的相应方法。
这种类与类之间的组合方式的设计思想成为CRP(组合复用原则)原则,即通过接口的组合将ADT各个功能的实现委托给外部具有相应功能的对象来完成。
这里大家可以看一下我的某个关于位置数量的package:
在这里插入图片描述
里面分别是双位置(对应航班)的接口及具体实现类、多位置(对应列车)的接口实现等等。
随后,我们在计划项ADT的接口中组合其对应所需要的特性的接口,以航班计划项的接口为例,我们组合了单个时间对、单个资源、双位置等特性的接口:
在这里插入图片描述
随后我们在计划项ADT的具体实现中,为这些接口分别设定对应的成员变量,从而将计划项ADT的方法实现委托给这些接口的实现类对象:
在这里插入图片描述
(这些成员变量的实例我们可以在creator中从客户端传进来)
方法委托,直接把实现委托给成员变量:
在这里插入图片描述

总结

这次Lab3的完成,有很大一部分时间花在了构思类的组合框架上,虽然指导书给出了相应的指导思想(CRP),但具体应用、掌握其要领还是花了我不少时间。不过我们可以看到,一旦完成了框架的建构,后面多个计划项的实现以及后期的需求变动导致的改动也轻松了不少。本次实验还涉及到了一些较好的设计模式以及可复用、可维护性相关的技术,这一篇博客就暂时先不做总结,我们下一篇再做讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值