HIT-SC-Chapter Ten
- HIT-SC-Chapter Ten
- 1 Software Maintenance and Evolution
- 2 Metrics of Maintainability
- 3 Modular Design and Modularity Principles
- 4 OO Design Principles: SOLID
- 5 Grammar-based construction
- (3) Recursion in grammars
- SUM
HIT-SC-Chapter Ten
Construction for Change
1 Software Maintenance and Evolution
-
steps:
-
处理来自用户报告的故障/问题
-
测试所做的修改
-
回归测试
-
记录变化
-
-
除了修复问题,修改中不能引入新的故障
-
最大的问题:修改后没有足够的文档记录和测试
软件维护类型
Software Evolution
-
软件演化:对软件进行持续的更新
-
大部分成本来自于维护阶段
-
-
“变化”在软件生命周期中是不可避免的!如何在最初的设计中充分考虑到未来的变化,避免因为频繁变化导致软件复杂度的增加和质量的下降?
-
2 Metrics of Maintainability
-
可维护性/可扩展性/灵活性/可适应性/可管理性/支持性
-
一些常用的可维护性指标
-
Cyclomatic Complexity 圈复杂度
- Measures the structural complexity of the code.
- 它是通过计算程序流中不同代码路径的数量来创建的。
- 程序中分支、嵌套、循环的多少,与程序的复杂度有关。
- 一个具有复杂控制流的程序将需要更多的测试来实现良好的代码覆盖,并且将更不容易维护
-
Lines of Code 代码行数 - Indicates the approximate number of lines in the code.
- 一个非常高的计数可能表明一个类型或方法试图做太多的工作,应该被拆分。
- 它还可能表明类型或方法可能很难维护
-
Halstead Volume:
-
a composite metric based on the number of (distinct) operators and operands in source code.
-
基于源代码中(不同的)运算符和操作数数量的复合度量。
-
Maintainability Index (MI)可维护性指数
- 计算0到100之间的索引值,表示相对容易维护代码。
- 高值意味着更好的可维护性。
-
计算依据:
-
HV
-
CC
-
LOC
-
COM
-
-
-
-
Depth of Inheritance 继承的层次数
-
Class Coupling 类之间的耦合度
-
Unit test coverage单元测试的覆盖度
-
3 Modular Design and Modularity Principles
模块化设计和模块化原则
Modular programming 模块化编程
- Modular programming is a design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality.
- ……
(1) Five Criteria for Evaluating Modularity
- Decomposability (可分解性)
- Are larger components decomposed into smaller components?
- Composability (可组合性)
- Are larger components composed from smaller components?
- Understandability (可理解性)
- Are components separately understandable?
- Continuity (可持续性) ——发生变化时受影响范围最小
- Do small changes to the specification affect a localized and limited number of components?
- Protection (出现异常之后的保护) ——出现异常后受影响范围最小
- Are the effects of run-time abnormalities confined to a small number of related components?
(2) Five Rules of Modularity Design
- Direct Mapping (直接映射)
- Few Interfaces (尽可能少的接口)
- Small Interfaces (尽可能小的接口)
- Explicit Interfaces (显式接口)
- Information Hiding (信息隐藏)
(3) Coupling and Cohesion
- Coupling
- 耦合是模块之间依赖关系的度量。如果一个模块中的更改可能需要另一个模块中的更改,则两个模块之间存在依赖关系。
- The degree of coupling between modules is determined by:
- 模块间接口数量
- 每个接口的复杂性
- Cohesion 内聚
- Cohesion is a measure of how strongly related the functions or responsibilities of a module are. 内聚性是衡量模块的功能或职责之间的关联程度。
- A module has high cohesion if all of its elements are working towards the same goal. 如果模块的所有元素都朝着相同的目标努力 ,则模块具有很高的内聚性。
- The best designs have high cohesion (also called strong cohesion) within a module and low coupling (also called weak coupling) between modules.
4 OO Design Principles: SOLID
面向对象设计的几个原则: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) Single Responsibility Principle (SRP)
不应该有多于1个原因让你的ADT发生变化,否则就拆分开
-
Responsibility: “a reason for change.” (责任:变化的原因)
-
SRP:
- There should never be more than one reason for a class to change. (不应有
多于1个的原因使得一个类发生变化) - One class, one responsibility. (一个类,一个责任)
- There should never be more than one reason for a class to change. (不应有
-
如果一个类包含了多个责任,那么将引起不良后果:
- 引入额外的包,占据资源
- 导致频繁的重新配置、部署等
-
-
(2) Open/Closed Principle (OCP)
(面向变化的)开放/封闭原则
-
Classes should be open for extension (对扩展性的开放)
- 模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化
-
But closed for modification. (对修改的封闭)
- 但模块自身的代码是不应被修改的
- 扩展模块行为的一般途径是修改模块的内部实现
- 如果一个模块不能被修改,那么它通常被认为是具有固定的行为
-
关键的解决方案:抽象技术
- 软件实体(类、模块、函数等)应开放以供扩展,但应关闭以供修改,即使用继承和组合/委派更改类的行为。
-
(3) Liskov Substitution Principle (LSP)
- 子类型必须能够替换其基类型
- 派生类必须能够通过其基类的接口使用,客户端无需了解二者之间的差异
(4) Interface Segregation Principle (ISP)
接口隔离原则
- 不能强迫客户端依赖于它们不需要的接口:
- 只提供必需的接口
- 不要强制类实现它们无法实现的方法
- 不要用很多方法污染接口
- 避免“fat”接口
(ISP) The Interface Segregation 界面分离
- 客户端不应依赖于它们不需要的方法
- 接口属于客户端,而不是层次结构。
- “胖”接口具有很多缺点
- 不够聚合
- 可分解为多个小的接口
(5) Dependency Inversion Principle (DIP)
依赖转置原则
- 高级模块不应该依赖于低级模块。两者都应该依赖于抽象。
- 抽象的模块不应依赖于具体的模块
- 具体应依赖于抽象
- 应该使用大量的接口和抽象!
5 Grammar-based construction
String/Stream based I/O
- 有一类应用,从外部读取文本数据,在应用中做进一步处理。
- 字节或字符序列可能是来自:
- A file on disk, in which case the specification is called the file format 文件格式
- 输入文件有特定格式,程序需读取文件并从中抽取正确的内容
- 从网络上传输过来的消息,遵循特定的协议
- 通过网络发送的消息,在这种情况下,规范是有线协议
- 用户在命令行输入的指令,遵循特定的格式
- 用户在控制台上输入的命令,在这种情况下,规范是命令行接口
- 内存中存储的字符串,也有格式需要
- A file on disk, in which case the specification is called the file format 文件格式
The notion of a grammar语法的概念
- 对于这些类型的序列,语法的概念是一个很好的设计选择
- 使用grammar判断字符串是否合法,并解析成程序里使用的数据结构
- 通常是递归的数据结构
- Regular expression 正则表达式
- 它是一种广泛使用的工具,用于许多字符串处理任务,这些任务需要对字符串进行反汇编、从中提取信息或转换。
- 解析器生成器是一种将语法自动转换为该语法的解析器的工具
自动机里面的正则表达式
(1) Constituents of a Grammar
- Terminals: Literal Strings in a Grammar
- 为了描述一串符号,无论它们是字节、字符还是从固定集合中提取的其他类型的符号,我们使用一种称为语法的紧凑表示。
- The literal strings in a grammar are called terminals 语法中的文字字符串称为终端/终结符
- 它们被称为终端,因为它们是表示字符串结构的解析树的叶子。
- They don’t have any children, and can’t be expanded any further.
- 我们通常把终端写在引号里,比如' http '或':'。
语法中的非终结符和产生式(产生式语法)
- A grammar is described by a set of productions 产生式节点,每个产生式节点都定义了一个非终止节点
- 非终结符就像一个变量,它代表一组字符串,其结果就是该变量的定义,它包含其他变量(非终结符)、操作符和常量(终结符)。
- 遵循特定规则,利用操作符、终止节点和其他非终止节点,构造新的字符串
- .非终结符是表示字符串的树的内部节点
- 非终结符就像一个变量,它代表一组字符串,其结果就是该变量的定义,它包含其他变量(非终结符)、操作符和常量(终结符)。
- A production in a grammar has the form
- nonterminal ::= expression of terminals, nonterminals, and operators
- One of the nonterminals of the grammar is designated as the root. 语法的一个非终结符被指定为根。
- 语法识别的字符串集与根非终结符匹配。
- This nonterminal is often called root or start. 根节点
(2) Operators in a Grammar
- Concatenation 连接, represented not by a symbol, but just a space
- x ::= y z x matches y followed by z
- Repetition 重复, represented by *:
- x ::= y* x matches zero or more y
- Union, also called alternation 选择, represented by |:
- x ::= y | z x matches either y or z
- 使用圆括号对操作符进行分组
- 优先级
- 按照惯例,后缀运算符*, ?和+具有最高优先级,这意味着它们首先应用。
- Concatenation is applied next. 接下来将应用串联。
- Alternation | has lowest precedence, which means it is applied last. 交替|的优先级最低,这意味着它是最后应用的。
- Parentheses can be used to override precedence:括号可用于替代优先级
- x ::= (y z | a b)* x matches zero or more yz or ab pairs
- m ::= a (b|c) d m matches a, followed by either b or c, followed by d
A small example
- 这个语法表示三个字符串的集合。
- 为了让它代表更多的url,我们允许任何小写单词来代替mit, stanford,谷歌,com和edu:
- 新的单词规则匹配零或多个小写字母的字符串,因此现在整体语法也可以匹配http://alibaba.com/和http://zyxw.edu/。
- 不幸的是,word也可以匹配空字符串,所以这个url语法也可以匹配http://./,这不是一个合法的url。
More grammar operators
- 其他运算符只是语法加持(即,它们等效于三大运算符的组合):
- Optional可选择的(0 or 1 occurrence), represented by ?:
- x ::= y? an x is a y or is the empty string
- 1 or more occurrences: represented by +:
- x ::= y+ an x is one or more y (equivalent to x ::= y y* )
- A character class [...], representing the length-1 strings containing any of the characters listed in the square brackets:
- x ::= [a-c] is equivalent to x ::= 'a' | 'b' | 'c'
- x ::= [aeiou] is equivalent to x ::= 'a' | 'e' | 'i' | 'o' | 'u'
- An inverted character class
[^...]
, representing the length-1 strings
containing any character not listed in the brackets:- x ::= [â-c] is equivalent to x ::= 'd' | 'e' | 'f' | ...(all other characters)
- Optional可选择的(0 or 1 occurrence), represented by ?:
(3) Recursion in grammars
-
Hostnames can have more than two components, and there can be an optional port number:
-
-
hostname is now defined recursively in terms of itself.
-
使用重复操作符,我们也可以不递归地写主机名,像这样:
- hostname ::= (word '.')+ word
(4) Parse Trees(正则语言里面的语法树)
-
将语法与字符串匹配可以生成一个解析树,该树显示字符串的各个部分如何对应于语法
的各个部分。 -
解析树的叶子用终端标记,表示已解析的字符串部分
-
They don’t have any children, and can’t be expanded any further
-
如果我们把叶子结点连在一起,就会得到原来的字符串。
-
-
-
More generalizations…
- 通用http以支持url可以拥有的附加协议,如ftp、https、…
- 将末尾的/泛化为斜杠分隔的路径,例如http://didit.csail.mit.edu:4949/homework/lab1/
- 允许主机名使用完整的合法字符集,而不是仅仅使用a-z字符,比如http://ou812.com/
(5) Markdown和HTML
-
Markup languages标记语言:
- represents typographic style in text.表示文本中的排印样式。
-
Markdown example for italics
- This is
_italic_
. - This is italic.
- This is
-
HTML example for italics
Here is an <i>italic</i> word.
- Here is an italic word.
-
为简单起见,我们假设格式分隔符之间的纯文本不允许使用任何格式标点符号,如_或<>。
-
-
Documenting like programming: Markdown, LaTeX
-
除了对排版美的追求,TEX使人们像编程一样写作文
-
TEX的版本号不是自然数列,也不是年份,而是从3开始,不断逼近圆周率(目前最新版本是3.14159265),意思是说:这个东西趋近完美,不可能再有什么大的改进了
-
设立了一个奖项:谁发现TEX的一个错误,就付他2.56美元,第二个错误5.12美元,第三个10.24美元……以此类推
(6) Regular Grammars and Regular Expressions
Regular grammar
-
正则语法:简化之后可以表达为一个产生式而不包含任何非终止节点
- 通过将每个非终结符(除了根终止符)替换为它的右手边,您可以将其简化为根的单个结果,右边只有终结符和操作符
-
Regular Expressions (regex)
-
终端和操作符的简化表达式可以写成更紧凑的形式,称为正则表达式。
- 正则表达式去掉了终端周围的引号以及终端和操作符之间的空格,因此它只包含终端字符、分组用的括号和操作符字符。
- 去除引号和空格,从而表达更简洁(更难懂)
-
-
正则表达式的可读性远不如原始语法,因为它缺少记录每个子表达式含义的
非终结名。 -
但是regex实现起来很快,许多编程语言中都有支持正则表达式的库。
-
Some special operators in regex
-
Context-Free Grammars上下文无关语法
-
通常,可以用语法系统表示的语言称为上下文无关语言。
-
Not all context-free languages are also regular; that is, some grammars can’t be reduced to single nonrecursive productions.
- 并非所有上下文无关语言都是正则;也就是说,有些语法不能简化为单个非递归结果。
- .HTML语法是上下文无关,但非正则。
-
大多数编程语言的语法也与上下文无关。
-
通常,任何具有嵌套结构(如嵌套括号或大括号)的语言都是上下文无关的,但不是正则的。
-
(7) * Parsers
Parser将输入文本转为parse tree
- parser:输入一段文本,与特定的语法规则建立匹配,输出结果
- 利用产生的parse tree,进行下一步的处理
- 表示语言表达式的递归抽象数据类型称为抽象语法树(AST)。
- Parser Generator 根据语法定义生成parser
- ……
(8) Using regular expressions in Java
- In Java, you can use regexes for manipulating strings (see String.split, String.matches, java.util.regex.Pattern).
- 在Java中,您可以使用正则表达式来操作字符串(参见String。分裂,字符串。比赛,java.util.regex.Pattern)
- 它们是Python、Ruby和JavaScript等现代脚本语言的一流功能,您可以在许多文本编辑器中使用它们进行查找和替换。
The java.util.regex
-
package primarily consists of three classes:
- Pattern是对regex正则表达式进行编译之后得到的结果
- Matcher:利用Pattern对输入字符串进行解析
- PatternSyntaxException对象是一个未检查的异常,它指出正则表达式模式中的语法错误。
-
Using regular expressions in Java
- Replace all runs of spaces with a single space:
- Match a URL:
- Extract part of an HTML tag:
字符类
- Metacharacters: <([{^-=$!|]})?*+.>
- 有两种方法强制将元字符视为普通字符:•
- 在元字符前面加一个反斜杠\•
- 将其包含在\Q(引号的开头)和\E(引号的结尾)中。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理