5.3 面向可维护性的构造技术

除了前面介绍的几种设计模式,还有基于状态的构造技术和基于语法的构造技术。

1 基于状态的构造技术
基于状态的程序设计
▪ 基于状态的编程是一种使用有限状态机(FSM)来描述程序行为的编程技术,即使用“状态”来控制程序流。
–例如,对于电梯,它可以是停止、向上移动、向下移动、停止、关闭门和打开门。
▪ 每一种都被认为是一种状态,接下来发生什么取决于电梯的当前状态。
–如果电梯刚刚关门,接下来可能发生什么情况?它可以停止,向上或向下移动。
–当电梯停下来时,你期望下一个动作是开门、向上或向下移动。

在这里插入图片描述
如果在ADT中使用大量的if else会使程序臃肿且难以维护

(1) Automata-based programming基于自动机的编程
基于自动机的程序设计 ▪ 基于自动机的编程是一种编程范式,在这种编程范式中,程序或其一部分被认为是有限状态机(FSM)或任何其他形式自动机的模型。
–将程序视为有限自动机。
–每个自动机一次只能执行一个“步骤”,程序的执行被分解成各个步骤。–这些步骤通过更改表示“状态”的变量的值相互通信。
–程序的控制流由该变量的值决定。
▪ 应用程序设计方法应类似于控制系统(自动机系统)的设计。

在这里插入图片描述
基于自动机的程序设计
▪ 程序执行的时间段清楚地划分为自动机的各个步骤。
–每个步骤实际上都是一个代码段的执行(所有步骤都是一样的),它只有一个入口点。这样的部分可以是一个函数或其他例程,或者只是一个循环体。
▪ 步骤之间的任何通信都只能通过名为state的状态实现。
–在任何两个步骤之间,程序不能有其状态的隐式组件,例如本地(堆栈)变量的值、返回地址、当前指令指针等–整个程序在进入自动机步骤的任意两个时刻的状态,只能在被视为自动机的状态。

▪ “state”变量可以是简单的枚举数据类型,但可以使用更复杂的数据结构。▪ 一种常见的技术是创建一个状态转换表,一个二维数组,包含表示每个可能状态的行和表示输入参数的列。–行和列满足的表的值是机器在满足这两个条件时应转换到的下一个状态。

(2) 状态模式(behavioral pattern)
需求:一个对象总是处于几种状态中的一种,每种状态下的行为不一样;可以使用if/else,但更好的解决方案是使用状态模式。

状态模式将对象在不同状态下的行为委托给“状态类”进行表达,对象的状态类可以进行改变,状态对象通常不包括任何属性。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:状态模式与if和else比更加灵活,当新增状态类时,对原有的状态类的修改也不会太大,对不同状态下的行为处理逻辑也更清晰。

(3) Memento Pattern
备忘录模式(behavioral)
需求:需要将对象还原回以前的状态(例如“撤消”或“回滚”操作)。
-在不违反封装的情况下,捕获并外部化对象的内部状态,以便稍后将对象返回到此状态

该设计模式包括:
– Originator - 需要“备忘”的类
– Caretaker - 添加originator的备忘记录和恢复
– Memento - 备忘录,记录originator对象的历史状态

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2 Grammar-based construction
语法驱动的构造

I/O流:从外部读取数据文本/往外部写数据文本
-磁盘文件:遵循文件格式规范
-网络消息:遵循网络协议
-控制台命令:遵循命令行格式

正则表达式-它是一个广泛使用的工具,用于许多需要反汇编字符串、从中提取信息或转换字符串的字符串处理任务。
▪ 语法分析器生成器是一种将语法自动转换为语法分析器的工具。
(1) 语法成分
终端:语法中的文本字符串
▪ 为了描述一系列符号,不管它们是字节、字符还是从固定集合中提取的其他某种符号,我们使用一种称为语法的紧凑表示法。
▪ 语法定义一组字符串。
–例如,url语法将指定HTTP协议中合法url的字符串集。▪ 语法中的literalstrings称为terminals,之所以称为terminals,是因为它们是表示字符串结构的解析树的叶子。
–我们通常用引号编写终端,如“http”或“:”。
语法中的非终结词与产生式
▪ 语法是由一组乘积共同描述的,其中每一个乘积定义一个非终结的正切-一个非终结的就像一个代表一组字符串的变量,而该乘积是该变量在其他变量(非终结)、运算符和常量(终端)方面的定义。非终端是表示字符串的树的内部节点。
▪ 语法中的产品具有以下形式:
非终结符::=终结符、非终结符和运算符的表达式
▪ 语法的一个非终结符被指定为根。
–语法识别的字符串集与根非终结符匹配。
–此非终结符通常称为根或开始。
(2) 语法中的运算符
在这里插入图片描述
按照惯例,后缀运算符*?,和+具有最高优先级,这意味着它们首先应用。
▪ 接下来应用连接
▪ | 具有最低的优先级,这意味着它是最后应用的。
▪ 括号可用于重写优先级:
–x::=(y z | a b)*x匹配零个或多个yz或ab对
–m::=a(b | c)d m匹配a,后跟b或c,后跟d
在这里插入图片描述
(4) 解析树

▪ 将语法与字符串匹配可以生成一个解析树,该树显示字符串的部分如何与语法的部分对应。
–解析树的叶子用端子标记,表示已解析的字符串部分。
–如果我们将叶子连接在一起,我们将得到原始字符串。

在这里插入图片描述

在这里插入图片描述

(5) 标记和HTML
标记语言:表示文本中的排版样式。
在这里插入图片描述
(6) 正则文法和正则表达式
正则语法:简化之后 可以表达为一个产生式而不包含任何非终止节点
▪ 终端和运算符的简化表达式可以用更紧凑的形式编写,称为正则表达式。
▪ 正则表达式去掉了端子周围的引号以及端子和运算符之间的空格,因此它只包含端子字符、用于分组的括号和运算符字符。
▪ 正则表达式也被简称为regex。
–正则表达式的可读性远远低于原始语法,因为它缺少记录每个子表达式含义的非终结名。
–但是regex实现起来很快,而且许多编程语言中都有支持正则表达式的库。
在这里插入图片描述
并非所有上下文无关的语言都是正则的。
(8) 在Java中使用正则表达式
▪ 正则表达式在编程中被广泛使用。
▪ 在Java中,可以使用正则表达式来操作字符串(请参见字符串.split, 字符串匹配, java.util.regex。模式)。
▪ 它们内置于现代脚本语言(如Python、Ruby和JavaScript)的一级特性中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
▪ Greedy : 匹配器被强制要求第一次尝试匹配时读入整个输入串,如果 第一次尝试匹配失败,则从后往前逐个字符地回退并尝试再次匹配,直 到匹配成功或没有字符可回退。
▪ Reluctant:从输入串的首(字符)位置开始,在一次尝试匹配查找中只勉 强地读一个字符,直到尝试完整个字符串。
▪ Possessive: 直接匹配整个字符串,如果完全匹配就匹配成功,否则匹配 失败。效果相当于equals()。
在这里插入图片描述
正则表达式的缺点:难以理解,难以更改

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值