软件的可维护性和复用性

本文探讨了软件可维护性与复用性的关系,强调在软件开发中,良好的设计应注重可扩展性、灵活性和可插入性,通过面向对象原则如OCP、LSP、DIP和CARP等来提高系统的可维护性和复用性,避免过度修改导致的维护困难和复用性损失。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

可维护性:

通常认为,一个易于维护的系统,就是复用率高的系统;而一个复用性好的系统,就是一个易于维护的系统。(虽然可维护性和可复用性两者是两个独立的目标,并不总是方向一致)。

在支持可维护性(Maintainability)的同时,提高系统的复用性(Reuseability)是核心问题。

A 软件的维护

  一件家用电器,常常是买下后一用好多年,在生命周期内,几乎没有维修费用:这表明轻视维护的思想根深蒂固。这是因为,一件家用电器的维护,知识保持或者恢复电器的某种操作性能所需要的时间和资源;软件的维护则不同:它不仅包括清除错误(重启和重新安装部署),还包括对已有性能的扩充,以满足新的设计要求。一个典型的例子就是新一代智能汽车的崛起对传统汽车提出的挑战,汽车开始变得像电脑,可以开机自动空中下载OTA升级。

家用电器的使用者不可能对一个黑白电视机进行改造,将它变为彩色电视,或者讲一个小电视改造为一个大电视。软件则不同,一个维护中的软件是一个不断再生的软件,就像一个“不断带来新礼物和使用体验的礼物”。软件的维护就是软件的再生。

一个好的软件设计,必须能允许新的设计要求能以较为容易和平稳的方式加入到已有的系统中去,从而使这个系统能够不断焕发出青春。我们可以简单称为它应具有可维护性。

B  一个典型的软件生命周期

一个软件项目开始了,系统分析师们拿到了系统的设计要求。系统的美,从分析师们头脑之中的美,然后存在于设计师绘制的设计图纸上,然后成为一个原型系统供用户评审,最后迭代开发成为一个真实、有血有肉的可交付客户使用的系统。无论从分析师、设计师还是到程序员,大家都觉得美丽绝伦;客户则从花出去的钱,一步步看到变成了现实(迭代多次交付的软件过程)。这个时候,新鲜交付的系统就像一副优美的画作一般,处处都是纯净优美的。

但不久事情就会出现变化。客户运行了一段时间,提出了一些“小小”的修改要求,虽然在迭代开发过程中,客户不断在发现和提出一些小小的修改要求我们都竭力满足了。由于在交付之后,这些修改与现有系统的设计并不一定相容,我们只好采取一些权宜之计,使得系统打过补丁之后更像画作上布满修补痕迹一样,失去了最初的纯净和完美,变得杂乱无章。其中有一些甚至变成了系统的丑陋之处。随着时间的流逝,这些甚至成为了系统中最主要的组成部分,到处是一些判断语句,如果xxx,那么yyy;如果xxxx,那么yyyy。日渐腐朽的代码,终于会被人们不断诅咒当年的设计者。

C 表面原因:设计师的无奈

用户要求的变化无常,系统设计没法跟上如此快速的变化。如果维护设计师和原始设计师不是同一组人员的话,还会有更多与技术无关的辩解。

首先,一个系统的原始设计不可能容纳和预测将来所有的性能要求和非功能性需求;

其次,维护设计师并不是原始设计师,不熟悉原始设计师的设计意图,即便原始设计的意图和框架可以容纳新的性能,维护设计师很可能以某种破坏原始设计意图和框架的方式将新性能加入进去。

由于这些改动是不同时期,由不同维护设计师以积累的方式进行的,只能是东拼西揍的权宜之计,缺乏整体性。

D 真正的原因

导致一个软件设计的可维护性差的真正原因有四个:过于僵硬(Rigidity)、过于脆弱(Fragility)、复用率低(Immobility)、黏度过高(Viscosity)。

Rigidity:很难在一个软件系统内加入新的性能,因为一个新的性能不仅意味着需要新模块,还要塞进去集成。一个软件系统一旦做好,就容易出现不能增加新功能的僵硬化情况。

Fragility:修改已有代码时,对一处的修改可能导致看起来没有什么关系的另一个地方发生故障,尽管修改前,设计师已经竭尽所能去预测所有可能的故障点。一碰就碎,是的软件系统过于脆弱。

Immobility:每当程序员发现一段代码、函数、模块所做的事情可以在别处被使用时,会发现,这些已有的代码会依赖一大堆其他的东西,因此,懒得去动脑筋复用,最常见到的做法就是“源代码复用”,这就是复用率低。

Viscosity:一个改动可以以符合原始设计框架进行,也可以破坏原始框架进行。后者采用的权宜之计方法,可以解决短期问题但会牺牲中长期利益。如果这种方法比第一种方法容易得多的话,程序员就会舍弃长期,搭建短路的特殊判断制造特例来完成修改。一个系统设计,如果总是让第二种办法比第一种办法容易,就被称为该设计黏度过高。

黏度过高的系统设计,会诱使程序员在对遗产系统再工程时采取错误的维护方案。

E 可维护性设计的目标:提高可复用性,提供可扩展性、灵活性、可插入性。

可扩展性:对应Rigidity的反面:

灵活性:对应Fragility的反面;

可插入性:对应Viscosity的反面。

可复用性:

A 传统的复用

代码级复用:复制剪贴。

由于同样的代码或类似代码被广泛复制到不同地点,当需要修改该代码时,需要处处独立修改拷贝。尤其是如果是多个组件中存在复制代码时,每个组件都需要独立的检测,代价也比较可观。

算法和数据结构的复用

例如排序查找算法,从已经得到很好研究的算法中选择一个,例如STL模板库。

可复用性与可维护性的关系:

  传统的复用时以破坏可维护性为代价的:例如若A和B同时使用模块C,如果A需要C增加新行为,而B并不需要甚至不允许时。如果放弃对C的修改,就能维持A与B共同对C的复用;反之,如果坚持对C做出修改,就会破坏C对B的维护性。可复用性和可维护性就像两个集合,支持可维护性的复用就是两个集合的交集。

B 面向对象的复用

数据的抽象、继承、封装和多态,可以让一个系统在更高层次上实现复用。数据的抽象(基类)和继承使得概念和定义可以复用(基类可以容纳派生类实例);多态使得实现和应用可以复用(接口使得功能应用可以抽象化被容纳)。如此,复用不再在较低的函数和算法上复用,转而集中到宏观业务逻辑上的抽象层次上复用。

可维护性复用以设计原则和设计模式为基础,下面给出结论:

三个设计目标:

(1)可扩展性:对应Rigidity的反面。可以考虑OCP(“开闭原则”)、LSP(里氏代换原则)、DIP(依赖倒转原则)和CARP(组合/聚合复用原则)。

(2)灵活性:对应Fragility的反面。由“开闭原则”、LoD(迪米特法则)、ISP(接口隔离原则)可以保证。

(3)可插入性:对应Viscosity的反面。用“开闭原则”、里氏代换原则、组合/聚合复用原则、依赖倒置原则。

综上所述,提高一个系统可维护性的同时,提高系统可复用性的指导原则就是抓住这些面向对象设计原则。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Valueyou24

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值