软件构造——面向可维护性的构造技术

面向可维护性的构造技术

本章面向另一个质量指标:可维护性——软件发生变化时,是否可以以很小的代价适应变化

软件维护

  1. 软件维护的概念:修复错误、改善性能
  2. 软件维护的类型:
  • 25%正确性维护
  • 21%适应性维护
  • 50%完善性维护
  • 4%预防性维护

可维护性指标

  1. 圈、环复杂度CC
  • 目的:衡量代码结构复杂度
  • 原理:CC = 独立路径的数量 = 边数 - 结点数 + 2
  • 一般来说CC越大程序要求更多的测试用例,程序可维护性越低
  1. 代码行数
  • 当一个类型或方法代码行数过大时我们应将其分成若干子类或子方法进行书写
  • 一般来说代码行数越多一个类型或一个方法可维护性越低
  1. Halsted Volume(HV)
  2. 可维护性指数MI:
  • 一个0-100之间的数值,用来衡量代码的维护性,MI指数越高意味着代码有着更好的可维护性
  • MI是一个关于四个变量的函数,HV越低,CC越低,LOC越低,COM越高则MI越大
    • HV:Halsted Volume
    • CC:Cyclomatic Complexity
    • LOC:The average number of lines of code per module
    • COM:The percentage of comment lines per module
  1. 继承的层次数
  2. 类之间的耦合度
  3. 单元测试的覆盖度

模块化设计与模块化原则

  1. 评估模块化的五个标准:
  • 可分解性:
    • 概念:将问题分解为各个可独立解决的子问题
    • 目的:使模块之间的依赖关系显式化和最小化
  • 可组合性
    • 概念:可以容易地将模块组合起来形成新的系统
    • 目的:使模块可在不同的环境下复用
    • 举例:数学库,UNIX指令
  • 可理解性
    • 概念:每个子模块都可被系统设计者容易的理解
  • 可持续性
    • 概念:规约中的小变化只会影响一小部分的模块而不会影响整个系统结构
    • 举例:符号型变量,模块提供的所有服务应通过统一标识提供
  • 出现异常之后的保护
    • 概念:运行时的不正常只会影响小部分模块
  1. 模块化设计的五条准则:
  • 直接映射
    • 概念:模块的结构与显示中问题的结构保持一致
    • 影响指标:可持续性,可分解性
  • 尽可能少的接口
    • 概念:模块应尽可能少的与其它模块通讯
    • 影响指标:可持续性、保护性、可理解性、可组合性
    • ”不要对太多人讲话“
  • 尽可能小的接口
    • 概念:如果两个模块通讯,那么它们应交换尽可能少的信息
    • 影响指标:可持续性、保护性
    • ”如果必须要讲话则不要讲太多“
  • 显式接口
    • 概念:当A与B通讯时,应明显的发生在A与B的接口之间
    • 影响指标:可分解性,可组合性,可持续性,可理解性
    • ”如果必须要讲这么多话则要公开大声讲话,不要私下讲话“
  • 信息隐藏
    • 概念:经常可能发生变化的设计决策应尽可能隐藏在抽象接口后面
    • 影响指标:可持续性
  1. 耦合与内聚
  • 耦合度Coupling:是一个类与其他类关联、知道其他类的信息或者依赖其他类的强弱程度的度量,是一个类对外的关联程度,如果一个类关联了很多类则耦合度就高
  • 聚合度Cohesion:是一个类内部承担职责的各子部分之间的相关程度,职责越相近聚合度就越高
  • 我们的目标:低耦合度,高聚合度

面向对象的设计原则:SOLID原则

SOLID原则是OO设计的五大重要原则的首字母缩写,遵循SOLID原则设计类和模块可以让软件更加健壮和稳定

  1. S(SRP):单一职责原则
  • 内容:一个类有且只有一个职责
  • 原理:一个类就像一个容器,可以添加任意数量的属性方法,但是当试图让一个类实现太多方法时,任何小的改变都会改变此类
  • 优点:让类变得简洁灵活
  • (SRP是最简单的原则,却是最难做好的原则)
  1. O(OCP):开放封闭原则
  • 内容:一个类应该对扩展开放,对修改封闭,这也意味着一旦创建了一个类并且应用程序的其他部分开始使用后就不应该对这个类进行修改
  1. L(LSP):里氏替换原则
  • 内容:派生的子类应该是可替换基类的,也就是说任何基类可以出现的地方子类也一定可以出现
  1. I(ISP):接口隔离原则
  • 内容:类不应该被迫依赖其不使用的方法,也就是说一个接口应该拥有尽可能少的行为
  1. D(DIP):依赖转置原则
  • 内容:高层模块不应该依赖于低层模块,两者都应该依赖于抽象类或者接口

语法驱动构造

  1. 使用场景:有统一格式的一组字符串
  • 有一类应用,从外部读取文本数据,在应用中做进一步处理
  • 输入文件中有特定格式,程序需要读取文件并从中抽取yuo确的内容
  • 从网络上传输过来的信息遵循特定的协议
  • 用户在命令行输入的指令,遵循特定的格式
  • 内存中存储的字符串,也有格式需要
  1. 语法操作符(按优先级由高到低)
  • 重复(克林闭包)

    • x ::= y*

    • x与 0个或多个y连接格式匹配

  • 出现至多一次

    • x ::= y?
    • x与y匹配或x是一个空串
  • 出现至少一次(正闭包)

    • x ::= y+
    • x与y匹配或与多个y连接匹配
  • 连接

    • x ::= y z
    • x 与 y连接z格式匹配
  • 选择

    • x ::= y|z
    • x与y匹配或与z格式匹配
  • 字符类

    • x ::= [a-c] , x ::= [aeiou]
    • x ::= ‘a’ | ‘b’ | ‘c’ , x ::= ‘a’|‘e’|‘i’|‘o’|‘u’
  • 颠倒字符类

    • x ::= [^a-c]
    • x ::= ‘d’|‘e’|‘f’|‘g’|….
  1. 正则表达式
  • . :匹配单个字符
  • \d:匹配数字[0-9]
  • \D:匹配非数字[^0-9]
  • \s:匹配空格,制表符,换行符
  • \S:匹配非空白[^\s]
  • \w:匹配[a-z] [A-Z] [0-9]
  • \W:匹配[^\w]
  • \.:匹配转义字符对应原始字符

在JAVA中使用正则表达式

  1. string.replaceAll:
  • String singleSpacedString= string.replaceAll(“ +”, “ ”);
  • 将所有的多个空格替换成一个空格
  1. match:
  • 格式:
    • Pattern regex = Pattern.compile(“http://([a-z]+\\.)”);
    • Matcher m = regex.matcher(string);
    • if(m.matches())
    • {String url = m.group(1);}
  1. 量词:
  • 贪婪的Greedy:匹配器被强制要求第一次尝试匹配时读入整个输入串,如果第一次尝试匹配失败,则从后往前逐个字符地回退并尝试再次匹配,直到匹配成功或没有字符可回退
  • 勉强的Reluctant:从输入串的首字符位置开始,在一次尝试匹配查找中只勉强地读一个字符,直到尝试完整个字符串
  • 独占的Possessive:直接匹配整个字符串,如果完全匹配就匹配成功,否则匹配失败,效果相当于equals()
    image
  1. 边界匹配符:

image

posted @ 2022-06-11 00:06  dcyyyyyy  阅读(54)  评论(0编辑  收藏  举报