JAVA SCRIPT设计模式--行为型--设计模式之Interpreter解释器模式(15)

news2024/11/19 9:33:49

         JAVA SCRIPT设计模式是本人根据GOF的设计模式写的博客记录。使用JAVA SCRIPT语言来实现主体功能,所以不可能像C++,JAVA等面向对象语言一样严谨,大部分程序都附上了JAVA SCRIPT代码,代码只是实现了设计模式的主体功能,不代表全部的正确,特此声明。若读者需要了解设计模式目录、原则、设计变化方向,环境相关等信息请查看设计模式开篇。


一、UML类图

参与者:

1.1 AbstractExpression(抽象表达式,如RegularExpression)

  • 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享

1.2 TerminalExpression(终结符表达式,如LiteralExpression)

  • 实现与文法中的终结符相关联的解释操作。
  • 一个句子中的每个终结符需要该类的一个实例。

1.3 NonterminalExpression(非终结符表达式,如AlternationExpression,RepetitionExpression,SequenceExpressions)

  • 对文法中的每一条规则R::=R1R2...Rn都需要一个NonterminalExpression类。
  • 为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。
  • 为文法中的非终结符实现解释(Interpret)操作。解释(Interpret)一般要递归地调用表示R1到Rn的那些对象的解释操作。

1.4 Context(上下文)

  • —包含解释器之外的一些全局信息。

1.5 Client(客户)

  • 构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
  • 调用解释操作。

二、意图

     给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子

三、适用性 

  1. the grammar is simple. For complex grammars, the class hierarchy forthe grammar becomes large and unmanageable. Tools such as parsergenerators are a better alternative in such cases. They can interpretexpressions without building abstract syntax trees, which can savespace and possibly time.语法很简单。对于复杂的语法 , 语法的类层次变得庞大而无法管理诸如解析器之类的工具是更好的选择。他们可以解释表达式,而无需构建抽象语法树,这可以节省空间,甚至可能节省时间。
  2. efficiency is not a critical concern. The most efficient interpretersare usually not implemented by interpreting parse trees directlybut by first translating them into another form. For example, regularexpressions are often transformed into state machines. But even then,the translator can be implemented by the Interpreter pattern, sothe pattern is still applicable. 效率不是一个关键问题。最高效的解释器通常不是通过直接解释语法分析树实现的 , 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种 情况下, 转换器仍可用解释器模式实现, 该模式仍是可用的。

四、优点和缺点

  1. 易于改变和扩展文法: 因为该模式使用类来表示文法规则 , 你可使用继承来改变或扩展该文法。已有的表达式可被增量式地改变 ,而新的表达式可定义为旧表达式的变体。
  2. 也易于实现文法: 定义抽象语法树中各个节点的类的实现大体类似。这些类易于直接编写,通常它们也可用一个编译器或语法分析程序生成器自动生成。
  3. 复杂的文法难以维护: 解释器模式为文法中的每一条规则至少定义了一个类(使用BNF定义的文法规则需要更多的类)。因此包含许多规则的文法可能难以管理和维护。可应用其他的设 计模式来缓解这一问题。但当文法非常复杂时, 其他的技术如语法分析程序或编译器生成器更为 合适。
  4. 增加了新的解释表达式的方式: 解释器模式使得实现新表达式“计算”变得容易。 例如, 你可以在表达式类上定义一个新的操作以支持优美打印或表达式的类型检查。如果你经常创建 新的解释表达式的方式, 那么可以考虑使用Visitor(5.11 )模式以避免修改这些代表文法的类。

五、示例代码

5.1  动机

         如果一种特定类型的问题发生的频率足够高 , 那么可能就值得将该问题的各个实例表述为 一个简单语言中的句子(then it might beworthwhile to express instances of the problem as sentences in a simple language)。这样就可以构建一个解释器 , 该解释器通过解释这些句子来解决该问题。

        例如,搜索匹配一个模式的字符串是一个常见问题。正则表达式是描述字符串模式的一 种标准语言。与其为每一个的模式都构造一个特定的算法,不如使用一种通用的搜索算法来解释执行一个正则表达式,该正则表达式定义了待匹配字符串的集合解释器模式描述了如何为简单的语言定义一个文法 , 如何在该语言中表示一个句子 , 以及如何解释这些句子。

        考虑以下文法定义正则表达式 :

expression ::= literal | alternation | sequence | repetition | 
'(' expression ')' 
alternation ::= expression '|' expression 
sequence ::= expression '&' expression 
repetition ::= expression '*' 
literal ::= 'a' | 'b' | 'c' | ... { 'a' | 'b' | 'c' | ... }* 

        符号expression是开始符号,literal是定义简单字的终结符。

        解释器模式使用类来表示每一条文法规则在规则右边的符号是这些类的实例变量。上面的文法用五个类表示:一个抽象类RegularExpression和它四个子类LiteralExpression(文字)、AlternationExpression(选择or)、SequenceExpression(sequ 跟随)和RepetitionExpression(重复)后三个类定义的变量代表子表达式。


        每个用这个文法定义的正则表达式都被表示为一个由这些类的实例构成的抽象语法树。例如,抽象语法树:

 
表示正则表达式:

raining&(dogs|cats)*

         如果我们为RegularExpression的每一子类都定义解释(Interpret)操作,那么就得到了为这些正则表达式的一个解释器。解释器将该表达式的上下文做为一个参数。上下文包含输入字符串和关于目前它已有多少已经被匹配等信息。为匹配输入字符串的下一部分,每一RegularExpression的子类都在当前上下文的基础上实现解释操作(Interpret)。例如

  • LiteralExpression将检查输入是否匹配它定义的字(literal)。
  • AlternationExpression将检查输入是否匹配它的任意一个选择项。
  • RepetitionExpression将检查输入是否含有多个它所重复的表达式

        等等。

        下面是Interpreter所要考虑的一些特殊问题:

  1. 创建抽象语法树解释器模式并未解释如何创建一个抽象的语法树。换言之,它不涉及语法分析。抽象语法树可用一个表驱动的语法分析程序来生成,也可用手写的(通常为递归下降法)语法分析程序创建,或直接由Client提供
  2. 定义解释操作并不一定要在表达式类中定义解释操作。如果经常要创建一种新的解释器,那么使用Visitor(5.11)模式将解释放入一个独立的“访问者”对象更好一些。例如,一个程序设计语言的会有许多在抽象语法树上的操作,比如类型检查、优化、代码生成,等等。恰当的做法是使用一个访问者以避免在每一个类上都定义这些操作
  3. 与Flyweight模式共享终结符在一些文法中,一个句子可能多次出现同一个终结符。此时最好共享那个符号的单个拷贝。计算机程序的文法是很好的例子—每个程序变量在整个代码中将会出现多次。在动机一节的例子中,一个句子中终结符dog(由LiteralExpression类描述)也可出现多次。

5.2  示例UML

目录结构:

5.2 AbstractExpression(抽象表达式,如RegularExpression)

  • 声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享

export default  class RegularExpression {
	 
    constructor( ) {
		 
    }
	/*解释
	 context :contains information that's global to the interpreter. 
	*/
    
	/**
	 * 实现了该正则表达式的一个解释器。定义抽象语法树的每一个类都实现了这一操作。
	 inputString 读入的部分输入字符串,返回object
	 */
	Match(context)
	{
		
	}
	 
  }

5.3 TerminalExpression(终结符表达式,如LiteralExpression)

  • 实现与文法中的终结符相关联的解释操作。
  • 一个句子中的每个终结符需要该类的一个实例。
import RegularExpression  from '../RegularExpression.js'; 
 
export default  class LiteralExpression extends RegularExpression {
   
    #components;
	constructor(components  ) {
	 super();
	 this.#components=components;
	}
   
	/*解释*/
	Match(context)
	{
		let inputString=context.GetInString();
		let arrayString=inputString.split(' ');//根据空格 获取token
		let sIndex=0;
		for(let n=0;n<arrayString.length;n++)
		{
			if(arrayString[n]==''){
				sIndex++
				continue;//过滤空字符
				}
		}
		if(sIndex<arrayString.length&&arrayString[sIndex]==this.#components)
		{
			context.SetMatchString(arrayString[sIndex]);
			context.SetInString(inputString.substr(arrayString[sIndex].length+sIndex)) ;
			return true
		}
		else
			return false;
	}
  }

5.4 NonterminalExpression(非终结符表达式,如AlternationExpression,RepetitionExpression,SequenceExpressions)

  • 对文法中的每一条规则R::=R1R2...Rn都需要一个NonterminalExpression类。
  • 为从R1到Rn的每个符号都维护一个AbstractExpression类型的实例变量。
  • 为文法中的非终结符实现解释(Interpret)操作。解释(Interpret)一般要递归地调用表示R1到Rn的那些对象的解释操作。
import RegularExpression  from '../RegularExpression.js'; 
 
export default  class AlternationExpression extends RegularExpression {
	#altercative1;
	#altercative2;
	constructor( altercative1,altercative2 ) {
	 super();
	 this.#altercative1=altercative1;
	 this.#altercative2=altercative2;
	}
	/*解释*/
	 
	Match(context)
	{
		if(this.#altercative1.Match(context))
		{
			return true;
		}else
		{
			if(this.#altercative2.Match(context))
				return true;
			else{
				 
				return false;
			}
		}
	}
  }
import RegularExpression from '../RegularExpression.js';

export default class RepetitionExpression extends RegularExpression {
	#repetition;
	constructor(repetition) {
		super();
		this.#repetition = repetition;
	}

	/*解释*/
	Match(context) {
		let bOnceFind = false;
		do {
			if (this.#repetition.Match(context)) {
				bOnceFind = true;
			} else {
				//没有匹配到
				break;
			}
		} while (true);
		if(!bOnceFind) context.SetMatchStringNull();
		return bOnceFind; 
	}
}
import RegularExpression  from '../RegularExpression.js'; 
 
export default  class SequenceExpression extends RegularExpression {
   
    #expression1;
	#expression2;
	constructor( expression1,expression2 ) {
	 super();
	 this.#expression1=expression1;
	 this.#expression2=expression2;
	}
   
	/*解释*/
	Match(context)
	{
		if(this.#expression1.Match(context))
		{
			 if(this.#expression2.Match(context))
				return true;
			else
			{
				//没有匹配到
				context.SetMatchStringNull();
			    return false
			}
			  
		}else
			context.SetMatchStringNull();
			return false
		 
	}
  }

5.5 Context(上下文)

  • —包含解释器之外的一些全局信息。

5.6 Client(客户)

  • 构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonterminalExpression和TerminalExpression的实例装配而成。
  • 调用解释操作。
import AlternationExpression from './Expression/impl/AlternationExpression.js';
import LiteralExpression from './Expression/impl/LiteralExpression.js';
import RepetitionExpression from './Expression/impl/RepetitionExpression.js';
import SequenceExpression from './Expression/impl/SequenceExpression.js';
import Context from './Expression/Context.js';


export default class Client {

	constructor(ctx, zooRect) {

		/**
		 * 构建语法树
		 */
		let aLiteralExpression = new LiteralExpression('raining');
		let aLiteralExpressiondogs = new LiteralExpression('dogs');
		let aLiteralExpressioncats = new LiteralExpression('cats');
		let anAlternationExpression = new AlternationExpression(aLiteralExpressiondogs, aLiteralExpressioncats);
		let aRepetitionExpression = new RepetitionExpression(anAlternationExpression);
		let aSequenceExpression = new SequenceExpression(aLiteralExpression, aRepetitionExpression);

		/**
		 * 匹配字符串
		 */
		let aString = 'raining cats dogs dogs cat';
		let context=new Context(aString);
		console.log(` 原始字符串  `+aString +'匹配表达式 raining&(dogs|cats)*');
		aSequenceExpression.Match(context);
		console.log(` 匹配的字符串  `+context.GetMatchString());
		
		let bString = 'raining cats dog dogs cat';
		let bcontext=new Context(bString);
		console.log(` 原始字符串  `+bString +'匹配表达式 raining&(dogs|cats)*');
		aSequenceExpression.Match(bcontext);
		console.log(` 匹配的字符串  `+bcontext.GetMatchString());
		
		
		let cString = 'raining cat dogs dog cat';
		let ccontext=new Context(cString);
		console.log(` 原始字符串  `+cString +'匹配表达式 raining&(dogs|cats)*');
		aSequenceExpression.Match(ccontext);
		console.log(` 匹配的字符串  `+ccontext.GetMatchString());
		
	}


}

5.8 测试HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
 
 
 <script  type="module" >
 import Client  from './Client.js'; 
 var x=document.getElementById("mycanvas")
 var ctx=x.getContext("2d") //create 2d object
let cl=new Client();
cl.main(ctx)

 </script>
</head>
<body>
<canvas id="mycanvas" width=900px height=900px></canvas>
    
</body>
</html>

测试结果:

Client.js:27  原始字符串  raining cats dogs dogs cat匹配表达式 raining&(dogs|cats)*
Client.js:29  匹配的字符串   raining cats dogs dogs
Client.js:33  原始字符串  raining cats dog dogs cat匹配表达式 raining&(dogs|cats)*
Client.js:35  匹配的字符串   raining cats
Client.js:40  原始字符串  raining cat dogs dog cat匹配表达式 raining&(dogs|cats)*
Client.js:42  匹配的字符串  

六、源代码下载

        下载链接:https://pan.baidu.com/s/1XuPqp84cccBNVkbnMY3sKw 
         提取码:q2ut

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/72329.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业微信如何设置文件权限?

当企业使用企业微信移动办公时&#xff0c;有些员工想要上传一些私人文件到企业微信微盘中“我的文件”里保存&#xff0c;但是又担心管理员可以看到&#xff0c;那么该如何设置文件权限呢&#xff1f; 前言 企业微信的会话内容存档功能可以在员工与客户知情的情况下存储聊天记…

linux系统怎么远程进服务器

linux系统怎么远程进服务器 我是艾西&#xff0c;还是有很多小白同学问我linux系统服务器怎么远程连接。那么今天我们重点来教教大家如何用电脑远程服务器配上图文教程&#xff0c;让不懂的新手小白一看就会&#xff0c;分分钟上手教程 远程服务器需要一台电脑俗称“PC”就是我…

i.e., namely, that is区别

i.e. 用作同位语&#xff0c;“即” To buy the car that I really want (i.e., a Tesla), I will have to work a lot of overtime. namely 用作插入语&#xff0c;表示列举&#xff0c;”也就是” The present paper evaluates the effect of major weather variables, nam…

阿里云国际版代充-对象存储OSS可应用哪些场景?

阿里云国际版对象存储OSS是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;可提供99.9999999999%&#xff08;12个9&#xff09;的数据持久性&#xff0c;99.995%的数据可用性。多种存储类型供选择&#xff0c;全面优化存储成本。 阿里云国际版OSS具有与平台无关的RE…

谷粒商城6:反向代理与性能优化

0.thymeleaf的复习 1.nginx反向代理 nginx的整体框架 访问流程 域名访问->在本地host文件中查找对应ip->找到了访问 找不到->DNS域名解析来解析域名到ip->找到了访问整体配置流程&#xff1a; 本机内&#xff1a; 查看域名的映射规则 在host文件中增加gulimall.co…

立创EDA极速入门(2)——完成一个STM32最小系统板

请提前观看&#xff1a;立创EDA极速入门&#xff08;1&#xff09;——熟悉PCB和立创EDA基本操作&#xff1b; 邀请加入嵌入式社区&#xff0c;您可以在上面发布问题&#xff0c;博客链接&#xff0c;公众号分享&#xff0c;行业消息&#xff0c;招聘信息等。 立创EDA绘制PCB只…

javaweb系统实现中遇到的问题

1.顶部导航栏 2.字符串转换成double 3.session的使用 4.eclipse如何debug 5.debug的查看变量的窗口 6.navicat设置默认值失效 7.javax.servlet.ServletException: 8.java.lang.NoSuchMethodError/java.lang.nullpointerexception 1.[html 简单顶部导航栏top-bar实现 csshtml](h…

高通Ride软件开发包使用指南(4)

高通Ride软件开发包使用指南&#xff08;4&#xff09;5 刷写SoC镜像5.2 高通镜像刷写加载器5.2.1 下载QFIL5.2.2 紧急下载模式设置SOC5.2.2.1 Switches5.2.2.2 测试自动化控制器脚本5.2.2.3 快速启动模式5.2.2.3.1 使用 Fastboot 擦除5.2.3 Flashing5.2.3.1 使用 Meta build 刷…

Unity Addressables资源管理 安装和使用本地加载

1.安装 打开Unity内置的 PackagerManager窗口 搜索Add即可找到 安装版本为1.19.19 2.添加Group 点击 Group 菜单 打开窗口 点击 Create Addressables Settings 创建可寻址设置 Assets下会生成一个 AddressableAssetsData 文件夹 其中可以看见面板中的 Default Local Grou…

猿如意中的【Dev C++】工具详情介绍

文章目录一、工具名称二、下载安装渠道2.1 什么是猿如意&#xff1f;2.2 如何下载猿如意&#xff1f;2.3 如何在载猿如意中下载开发工具&#xff1f;三、工具介绍四、软件截图五、软件使用教程六、体验感受一、工具名称 Java SE Development Kit 8 二、下载安装渠道 Java SE…

计算机毕业论文java毕业设计选题源代码javaweb党员信息管理系统

&#x1f496;&#x1f496;更多项目资源&#xff0c;最下方联系我们✨✨✨✨✨✨ 目录 Java项目介绍 资料获取 Java项目介绍 3.1.1 技术可行性 本系在架构选择上采用了当今使用较为广泛的B/S&#xff0c;本次毕业设计采用的B/S的优点在开发好程序后可以随意根据客户提出的…

神级框架 - MyBatis【初阶】

目录 1. 什么是 MyBatis 2. 如何学习 MyBatis 2.1 搭建 MyBatis 开发环境 2.2 使用 MyBatis 模式和语法操作数据库 2.2.1 MyBatis 的组成 2.2.2 MyBatis 实现查询功能 2.2.3 MyBatis 实现新增功能 2.2.3 MyBatis 实现删除功能 2.2.3 MyBatis 实现修改功能 3. 在 MyBatis…

XC7A50T-1FTG256I、XC6SLX150-2FGG900I嵌入式FPGA 技术参数

XC7A50T-1FTG256I IC FPGA 170 I/O 256FTBGA&#xff08;图左&#xff09; 说明&#xff1a;Artix-7 FPGA能够在多个方面实现更高的性价比&#xff0c;这些方面包括逻辑、信号处理、嵌入式内存、LVDS I/O、内存接口&#xff0c;以及收发器。Artix-7 FPGA非常适合用于需要高端功…

论文阅读笔记 | 三维目标检测——PV-RCNN++算法

如有错误&#xff0c;恳请指出。 文章目录1. 背景2. 网络结构2.1 Sectorized Proposal-Centric SamplingProposal-Centric FilteringSectorized Keypoint Sampling2.2 VectorPool Aggregation3. 实验结果paper&#xff1a;《PV-RCNN: Point-Voxel Feature Set Abstraction With…

STM32F4 | GPIO工作原理和配置 | GPIO库函数 | IO口操作步骤

文章目录一、GPIO基础知识1.GPIO是什么&#xff1f;2.引脚和GPIO的区别和联系&#xff1f;3.绝多数引脚都是GPIO&#xff0c;有限的引脚怎么实现更多的功能&#xff1f;4. 怎么知道具体的芯片外设资源?5.怎么查看GPIO引脚功能&#xff1f;二、GPIO的8种工作模式三、GPIO寄存器…

腾讯Robotics X Lab低电压电刺激触觉方案,单手指25个电极

关于体感手套的案例&#xff0c;青亭网曾经报道过许多种&#xff0c;有低成本的DIY阻力模拟手套&#xff0c;也有价格昂贵的启动微流体VR手套方案&#xff0c;或是基于SMA驱动器、SMI压力传感器的手套技术。但是&#xff0c;要模拟人类体感系统多样且敏感的触觉体验&#xff08…

TI Lab_SRR学习_3 速度扩展_3完结篇 interFrameProcessing

这篇信息量有点大,为了方便理解,还是先把帮助理解的图放在这里。 MmwDemo_interFrameProcessing函数的代码比较长,分段来看。先将数据从1DFFT的结果从L3内存中的radarCube移动到L1内存中的dstPingPong。for循环表示每一个RangeBins都要进行多普勒FFT等处理。从这里开始,可以…

Java——反射详解

目录 一、概念 二、功能 三、反射相关的重要的类 3.1 class类 3.2 获取class类的方法 3.3 class类中的方法 3.4 Field类方法 3.5 打破封装 一、概念 反射库&#xff08;reflection library&#xff09;提供了一个非常丰富且精心设计的工具集&#xff0c;以便编写能够动态…

口腔医院管理系统 | 口腔医院小程序 | 数字化门店转型

人们生活质量提升&#xff0c;在饮食方面不仅吃的饱&#xff0c;而且吃的好&#xff0c;相应的口腔问题就随之增多了&#xff0c;市面上的口腔医院不少&#xff0c;就诊的患者也不少。 目前&#xff0c;随着消费升级/互联网信息便捷化的大场景下&#xff0c;无论口腔门店经营还…

【Python项目】圣诞节快到了,Python基于海龟(turtle)实现的圣诞树效果,是好几个哟 | 附源码

前言 halo&#xff0c;包子们上午好 圣诞节快到了 今天我的好兄弟们安排了一波圣诞节的Python代码 主要是用海龟&#xff08;turtle&#xff09;画图实现的&#xff0c;非常简单的啦 话不多说&#xff0c;直接开整 相关文件 关注小编&#xff0c;私信小编领取哟&#xff01;…