其他分享
首页 > 其他分享> > 软件构造-10 面向可维护性的构造技术

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

作者:互联网

本章面向可维护性:软件发生变化时,是否可以以很小的代价适应变化?

(本章偏理论,主要为记忆性内容,本博客仅为简单的记录与整理)

 

1.软件可维护性及其演化

     

2.可维护性指标

     1.可维护性别名:可维护性,可扩展性,灵活性,可适应性,可管理性,支持性

     2.code review时关于可维护性经常会问的问题:

               设计结构是否足够简单

               模块之间是否松散耦合

               模块内部是否高度聚合

               是否使用非常深的继承树

               是否使用delegation替代继承

               代码的圈/环复杂度是否太高

               是否存在重复代码

    3.常用可维护性度量:

               1)圈/环复杂度:独立路径的数量 CC=number of areas

               2)代码行数

               3)Halstead Volume:多少独立算符

               4)可维护性指数(MI):

                  

                5)继承的层次数

                6)类之间的耦合度(尽量减少非常复杂的相互调用)

                7)单元测试的覆盖度

 

3. 模块化设计和模块化原则

               模块化编程:高内聚,低耦合(多模块之间关联较小,防止一个模块的大幅度改变影响另一个模块),分离关注点,信息隐藏

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

  1. 可分解性:能否容易分解成各个可独立解决的子问题,是模块之间的依赖关系显式化和最小化
  2. 可组合性:能够容易将多个模块组合起来形成新的系统,使模块在不同的环境下复用
  3. 可理解性:每个部分都可以被独立的理解
  4. 可持续性:发生变化时受影响范围最小
  5. 出现异常之后的保护:出现异常后受影响范围最小

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

  1. 直接映射:模块的结构与现实世界中问题领域的结构保持一致-》持续性,可分解性
  2. 尽可能少的接口:模块应尽可能少的与其他模块通讯-》可持续性、保护性、可理解性、可组合性
  3. 尽可能小的接口:如果两个模块通讯,那么它们应交换尽可能 少的信息-》可持续性,保护性
  4. 显式接口:当A与B通讯时,应明显的发 生在A与B的接口之间-》可分解性、可组合性、可持续性、 可理解性

       

        5.信息隐藏:经常可能发生变化的设计决策应 尽可能隐藏在抽象接口后面

(3)耦合和内聚:

        1.耦合:模块间的接口数目,每个接口的复杂度

        2.内聚:模块内部的方法联系是否紧密

 

4. OO设计原则:SOLID

      (SRP) The Single Responsibility Principle 单一责任原则

      (OCP) The Open-Closed Principle 开放-封闭原则

      (LSP) The Liskov Substitution Principle Liskov替换原则

      (DIP) The Dependency Inversion Principle 依赖转置原则

      (ISP) The Interface Segregation Principle 接口聚合原则

 

(1)SRP:单一责任原则

            1)ADT中不应该有多于1个原因让其发生变化,否则就拆分开

            2)责任:变化的原因

            3)不应有多于1个的原因使得一个类发生变化

            4)包含多个责任会导致:– 引入额外的包,占据资源

                                                      – 导致频繁的重新配置、部署等

            5)一个类,一个责任

(2)OCP:(面向变化的)开放/封闭原则

            1)对扩展性的开放:模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化

            2)对修改的封闭:但模块自身的代码是不应被修改的/扩展模块行为的一般途径是修改模块的内部实现/如果一个模块不能被修改,那么它通常被认为是具有固定的行为

            3)关键解决方案:抽象技术(尽量少用具体的)

(3)LSP:Liskov替换原则

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

(4)ISP:接口隔离原则

             1)不能强迫客户端依赖于它们不需要的接口:只提供必需的接口

             2)避免接口污染/避免胖接口

(5)DIP:依赖转置原则

             1)高层模块不应该依赖于低层 模块,二者都应该依赖于抽象

             2)抽象不应该依赖于实现细节,实现细节应该依赖于抽象

             OO设计的两大武器:抽象(LSP,DIP,OCP)/分离(SPR,ISP)

 

5. 语法驱动的构造

            有一类应用,从外部读取文本数据,在应用中做进一步处理 

            正则表达式:根据语法,开发一个它的解析器,用于后续的解析(不变的直接用‘’里的字符表示,其余可变的用符号组合表示,中间有比较复杂的模块就进行命名,单独脱离出来也写成一个表达式,比如下面eg中的hostname)

 

(1)基本操作:

            – Concatenation 连接: x ::= y z     (x匹配y与z连接)

            – Repetition 重复:     x ::= y*         (x匹配0或更多个y)(自动机里的克林闭包?)

            – Union 选择 :        x ::= y | z         (x匹配y或者z)

           eg:

          

(2)更多操作:

          1)选择 (出现0或1次),用 ? 表示 :

                    x ::= y?         (x匹配y或者空)

          2)出现1次或更多次 ,用 + 表示:

                    x ::= y+         (x匹配一个或更多y,与 x ::= y y*相等 )

          3)字符类 [...],表示长度为 1 的字符串,其中包含任何一个方框中列出的字符:

                    x ::= [a-c]   等同于  x ::= 'a' | 'b' | 'c'

                    x ::= [aeiou]   等同于   x ::= 'a' | 'e' | 'i' | 'o' | 'u'

          4) 倒排字符类 [^...],表示长度为 1 的字符串,其中包含括号中未列出的任何字符:

                    x ::= [^a-c]  等同于 x ::= 'd' | 'e' | 'f' | ...

(3)优先级:* ? +优先级最高,连接次之,| 最低

(4)在Java中使用正则表达式:

           1)使用java.util.regex包中的三个类:

                    1>Pattern:Pattern对象是对regex正则表达式进行编译之后得到的结果

                    2>Matcher: 利用Pattern对输入字符串进行解析

                    3>PatternSyntaxException:object 是一个未经检查的异常,表示正则表达式中的语法错误

           2)eg:

                  

 

 

 (5)字符类:

                    

 

(6)预定义字符类:

                   

 

 

 (7)量词:

                 

 

标签:10,原则,字符,接口,可维护性,模块,构造,Principle
来源: https://www.cnblogs.com/redTide/p/16335928.html