【软件构造】课件精译(十三)面向可维护性的软件构造思想与原则

一、软件维护和演化

什么是软件维护
在软件发布后,修改软件以修正错误 和提升性能。
在这里插入图片描述
运维工程师
修复代码后
测试所做的修改、回归测试、记录变化
除了修复问题,修改中不能引入新的故障,最大的问题:修改后没有足够的文档记录和测试
几种软件维护类型
纠正性维护、适应性维护、完善性维护、预防性维护
软件演化
软件演化:对软件进行持续的更新
软件的大部分成本来自于维护阶段
在这里插入图片描述
软件演进中的Lehman法则
在这里插入图片描述
软件需要使用不同的需求和环境。
软件熵
当一个系统被修改后,其混乱程度或者熵趋向于增加。
软件的生命模式
在这里插入图片描述
软件维护和演进的目标
提高软件的适应性,延续软件的生命
在这里插入图片描述
维护不只是运维工程师的工作
软件维护不仅仅是运维工程师的工作,而是从设计和开发阶段就开始了
设计和开发者需要考虑软件未来的变化和扩展
设计方案的“easy to change”
这也就是我们说的软件构造的可维护性、可扩展性和灵活性。
面向可维护性的软件构造的例子
模块化、OO设计原则、OO设计模式、基于状态的构造技术、表驱动的构造技术、基于语法的构造技术

二、可维护性的度量

可维护性的别名
可扩展性、灵活性、可适应性、可管理性、支持性
可维护性的问题
设计结构是否足够简单?
模块之间是否松散耦合?
模块内部是否高度聚合?
是否使用了非常深的继承树,是否使用了delegation替代继承?
代码的圈复杂度是否太高?
是否存在重复代码?
一些常用的可维护性度量
圈复杂度(CC):独立路径的个数,如果越多需要更多的测试
在这里插入图片描述
代码行数(LOC):每个模块的平均代码行数
Halstead Volume(HV):运算符和操作数的数目
可维护性指数(MI):基于HV、CC、LOC、COM(每个模块的注释行百分比)
在这里插入图片描述
继承的层次数
类之间的耦合度
单元测试的覆盖度
在这里插入图片描述
(具体在第九章讨论)
Linux内核中每个函数的平均复杂性
在这里插入图片描述
降低的平均值只是因为有了更多有相对低复杂性的函数。
Linux内核的可维护性指数(MI)
在这里插入图片描述

三、模块化设计和模块化原则

模块化编程
模块化编程是将程序的功能分散到独立可交互的模块中,是高层的功能分解技术
高内聚、低耦合、分离关注点、信息隐藏

(1)评估模块性的五个标准

可分解性、可组合性、可理解性、可持续性(发生变化时受影响范围最小 )、出现异常之后的保护(出现异常后受影响范围最小)
可分解性
将问题分解为各个可独立解决的子问题,从而使模块之间的依赖关 系显式化和最小化。
在这里插入图片描述
可组合性
可容易的将模块 组合起来形成新的系统,目标是使模块可在不同的环境下复用。
在这里插入图片描述
可理解性
指每个子模块都可被系统设计者容易的理解。
在这里插入图片描述
可持续性
小的变化将只影响一小部分模块,而不会影响整个体系结构。
在这里插入图片描述
保护性
运行时的不正常将局限于小范围模块内。
在这里插入图片描述

(2)模块化设计的五个规则

直接映射、尽可能少的接口、尽可能少的接口、显式接口、信息隐藏
直接映射
模块的结构与现实世界中问题领域的结构保持一致
受影响的评价标准:可持续性,可分解性
尽可能少的接口
模块应尽可能少的与其他模块通讯
受影响的评价标准:可持续性、保护性、可理解性、可组合性
”不要对太多人讲话…”
尽可能小的接口
如果两个模块通讯,那么它们应交换尽可能 少的信息
受影响的评价标准:可持续性、保护性
”不要讲太多…”
显式接口
当A与B通讯时,应明显的发生在A与B的接口之间
受影响的评价标准:可分解性、可组合性、可持续性、 可理解性
反例:
在这里插入图片描述
”公开的大声讲话…不要私下嘀咕…”
信息隐藏
经常可能发生变化的设计决策应尽可能隐藏在抽象接口后面
受影响的评价标准:可持续性
Example 1
在这里插入图片描述
在这里插入图片描述
Example 2
在这里插入图片描述

(3)耦合和内聚

耦合
耦合是模块之间依赖性的度量。 如果一个模块中的更改可能需要更改另一个模块,则两个模块之间存在依赖关系。通常由接口数量和接口复杂度来评价。
内聚
内聚是衡量模块的方法或职责的相关程度。
内聚和耦合
最佳的设计模式是高内聚、低耦合。
在这里插入图片描述
内聚和耦合之间的权衡
当耦合高时,内聚往往较低,反之亦然。
在这里插入图片描述

四、OO设计原则:SOLID

SOLID:五类设计原则
SOLID是指如下五个原则:
在这里插入图片描述

(1)单一责任原则(SRP)

不应该有多于1个原因让你的ADT发生变化,否则就应该拆分开
一个类,一个责任
反例
在这里插入图片描述
在这里插入图片描述

(2)开放/封闭原则(OCP)

OCP对扩展是开放的 ,对修改是封闭的,应通过继承和组合改变/扩展功能。模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化,但模块自身的代码是不应被修改的;扩展模块行为的一般途径是修改模块的内部实现;如果一个模块不能被修改,那么它通常被认为是具有固定的行为。
关键的解决方案:抽象技术
在这里插入图片描述
举例
在这里插入图片描述
这样的设计存在很多问题,代码冗杂而且不易扩展。调用时也需要很多If-Else或者Case语句。
在这里插入图片描述
上面这个方法便解决了这个问题,通过抽象类Shape作为参数类型,实现多态性,并且易于扩展。
另外, 当软件系统必须支持一组替代方案时,系统中应该有且只有一个模块知道方案的详尽列表。

(3)里氏代换原则(LSP)

子类型必须能够替换其基类型
派生类必须能够通过其基类的接口使用,客户端无需了解二者之间的差异

(4)接口隔离原则(ISP)

不能强迫客户端依赖于它们不需要的接口:只提供必需的接口,而“胖”接口具有很多缺点,例如不够聚合。
在这里插入图片描述
举例
在这里插入图片描述
上图左侧是反例,右侧是修改方法。第一个例子将接口合并,从而得到“胖”接口;第二个将功能分解开,从而可以根据需要选择接口。
在这里插入图片描述

(5)依赖转置原则(DIP)

抽象的模块不应依赖于具体的模块,具体应依赖于抽象。或者说高层模块不应该依赖于低层模块,二者都应该依赖于抽象,抽象不应该依赖于实现细节,实现细节应该依赖于抽象。
举例
在这里插入图片描述
在这里插入图片描述
修改为接口后,便可以使用多种具体的Finder类型。换句话说: delegation的时候,要通过interface建立联系,而非具体子类。
再看下面这个例子:
在这里插入图片描述
通过抽象类,上层client的代码面向抽象接口编程, 隔离对下层具体实现机制的直接接触。
在这里插入图片描述
为什么要遵守DIP原则?
类的契约形式化,通过前置和后置条件,清晰定义子程序的功能。
小结:OO设计的两大武器
在这里插入图片描述

五、OO设计原则:GRASP

GRASP是General Responsibility Assignment Software Patterns (principles)的首字母缩写,意思是通用责任分配软件模式 (原则),是关于如何为“类”和“对象”指派“职责”的一系列原则。
什么是责任
主要分为两种:掌握和操作
责任和方法
在这里插入图片描述
责任通过方法实现,例如上图中makePayment意味着Sale对象有责任创建Payment对象。

GRASP包括什么?
(这些内容在本章不是重点,所以简单介绍不做具体举例

(1)控制器(Controller)

问题:谁负责处理系统输入事件?
解决方案:将系统输入事件处理由统一的外观控制器类负责,某个用例的场景控制由用例控制器负责。
控制器类本身负责收发工作,具体执行通过委托机制进行指派。

(2)信息专家(Information Expert)

问题:将责任分配给对象的一般原则是什么?
解决方案:拥有信息的类负责相应的责任。

(3)创建器(Creator)

问题:谁应该负责创建某个类的新实例?
解决方案:如果出现以下情况,B类有责任创建A类实例:
B聚合或“包含”A对象
B紧密使用A对象
B具有A的初始化数据
B是A对象的创建者

(4)低耦合(Low Coupling)

问题:如何支持低依赖性,低变化影响和增加重用?
解决方案:分配责任,使耦合保持低水平。

(5)高内聚(High Cohesion)

问题:如何保持复杂性可管理?
解决方案:分配责任,使凝聚力保持高水平。

(6)间接(Indirection)

问题:在哪里分配责任,避免直接耦合两个(或更多)的东西? 如何解耦对象以便支持低耦合并且重用潜力仍然更高?
解决方案:将责任分配给中间对象,以避免直接耦合。

(7)多态性(Polymorphism)

问题:如何根据类型处理替代方案? 如何创建可插拔的软件组件?
解决方案:当相关的替代或行为因类型(类)而异时,使用多态操作将行为的责任分配给行为变化的类型。

(8)防止变异(Protected variations)

问题:如何使对象或系统的内部不稳定性不会对其他元素产生不良影响?
解决方案:确定将会发生的变化,分配责任以创建稳定的接口。

(9)纯虚构(Pure fabrication)

问题:无法依靠专家模式实现高内聚和低耦合时该怎么办?
解决方案:设计虚构的类实现高内聚低耦合和复用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值