设计模式----解释器模式

一、简介

        解释器模式使用频率并不高,通常用来构建一个简单语言的语法解释器,它只在一些非常特定的领域被用到,比如编译器、规则引擎、正则表达式、sql解析等。

        解释器模式是行为型设计模式之一,它的原始定义为:用于定义语言语法规则表示,并提供解释器来处理句子中的语法。

        我们通过一个例子来解释下解释器模式,假设我们设计一个软件来进行加减计算,我们第一想法就是使用工具类,提供对应的加法和减法的工具方法。

public int add(int a,int b){
return a+b;
}

public int add(int a,int b,int c){
return a+b+c;
}
......

上面的形式比较单一、有限如果形式变化非常多,这就不符合要求,因为加法和减法运算,两个运算符数组可以有无限种合作方式,比如1+3+2+1-5....

        解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。

二、结构

        解释器模式由以下几种角色组成:

        ①抽象表达式角色:定义解释器的接口,约定解释器的操作,主要包含解释方法interoret

        ②终结符表达式角色:用来实现文发中与终结符相关的操作,文法中的每一个终结符都有一个具体的终结符表达式与之对应

        ③非终结符表达式:用来实现文法中与非终结符相关的操作,文法中每条规则都对应一个非终结符表达式

        ④上下文类:通常包含各个解释器需要的数据或者是公共的功能,一般用来传递所有解释器共享的数据。

三、实现

        我们定义一个进行加减乘除计算的语言,语法规则如下:

        ①运算符只包含加减乘除,并且没有优先级概念

        ②表达式中,先写数字后写运算符,空格隔开

// 表达式接口
public interface Expression {
    int interpret();
}

// 加法解释器
public class AddExpression implements Expression {
    private Expression left;
    private Expression right;
    
    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 减法解释器
public class SubtractExpression implements Expression {
    private Expression left;
    private Expression right;
    
    public SubtractExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public int interpret() {
        return left.interpret() - right.interpret();
    }
}

// 乘法解释器
public class MultiplyExpression implements Expression {
    private Expression left;
    private Expression right;
    
    public MultiplyExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}

// 除法解释器
public class DivideExpression implements Expression {
    private Expression left;
    private Expression right;
    
    public DivideExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public int interpret() {
        try {
            return left.interpret() / right.interpret();
        } catch (ArithmeticException e) {
            System.out.println("除数不能为0");
            return -1;
        }
    }
}

// 数字解释器
public class NumberExpression implements Expression {
    private int number;
    
    public NumberExpression(int number) {
        this.number = number;
    }
    
    @Override
    public int interpret() {
        return number;
    }
}

现在我们可以使用这些类来解析四则运算表达式了。例如,对于表达式 “1 + 2 * 3 - 4 / 2”我们可以使用以下代码来解析该表达式:

Expression expression = new SubtractExpression(
                                new AddExpression(
                                    new NumberExpression(1),
                                    new MultiplyExpression(
                                        new NumberExpression(2),
                                        new NumberExpression(3)
                                    )
                                ),
                                new DivideExpression(
                                    new NumberExpression(4),
                                    new NumberExpression(2)
                                )
                            );
int result = expression.interpret();
System.out.println("计算结果为:" + result);

四、总结

优点

①易于改变可扩展文法,因为在解释器模式中实用类来表示语言的文法规则的,因此可以通过继承等机制改变或扩展文法,每一个文法规则都可以表示为一个类,因此我们可以快速的实现一个迷你的语言

②实现文法比较容易,在抽像语法术中每一个表达式节点的实现方式都是相似的,这些代码不特别复杂

③增加新的解释表达式比较方便,如果用户增加新的解释表达式,只需要对应增加一个新的表达式类就可以,原有的表达式不需修改,符合开闭原则

缺点

①对于复杂文法难以维护,在解释器中,一条规则至少要定义一个类,因此一个语言中有太多的文法规则,那么就会使类的个数急剧增加,导致系统的维护难以管理。

②执行效率低,在解释器模式中,大量的使用循环和递归调用,所以复杂的句子执行起来比较繁琐

使用场景

①当语言的文法比较简单时,并且执行的效率不是关键问题的时候

②当问题重复出现,且可以用一种简单的语言来表达

③当一个语言要解释执行,并且语言中的句子可以表示为一个抽象的语法树的时候。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ZKP Algorithms for Efficient Cryptographic Operations 1 (MSM Pippenger)

MIT IAP 2023 Modern Zero Knowledge Cryptography课程笔记 Lecture 6: Algorithms for Efficient Cryptographic Operations (Jason Morton) Multi-scalar Multiplication(MSM) Naive: nP (((P P) P) P)… (2(2P))…Binary expand $n e_0e_1\alphae_2\alpha2\dots\e_{\…

嵌入式开发必须学习qt吗?

嵌入式开发必须学习qt吗? 在开始前我有一些资料,是我根据自己从业十年经验,熬夜搞了几个通宵,精心整理了一份「 嵌入式的资料从专业入门到高级教程工具包」,点个关注,全部无偿共享给大家!&#…

JAVA的拼图游戏

看好路径 MyActionListener public class MyActionListener implements ActionListener {Overridepublic void actionPerformed(ActionEvent e) {System.out.println("按钮被点击了");} }MyJFrame public class MyJFrame extends JFrame implements ActionListener…

计算机网络——数据链路层(三)

前言: 前面我们已经对计算机网络的物理层有了一个大概的了解,今天我们学习的是物理层服务的上一层数据链路层,位于物理层和网络层之间。数据链路层在物理层提供的服务的基础上向网络层提供服务,其最基本的服务是将源自物理层来的数据可靠地传…

51单片机拆字程序实验

一、实验内容 1.基本要求 熟悉51仿真系统;设计并单步调试,实现将R5中数值(初值为本人学号后两位)拆分成两位独立的数据分别存于R6,R7中; 2.扩展要求 将R6,R7中的被拆出来的一位HEX数据转换为可显示的ASCII编码&…

C++笔试训练day_2

文章目录 选择题7. 编程题1.2. 选择题 (6)因为p2被const修饰所以p2不可以被改变,但是p2的指向可以被改变 (7)因为指针p3被const修饰,所以p3的指向不能被改变,但是*p3可以被改变 int main() {in…

【基于激光雷达的路沿检测用于自动驾驶的真值标注】

文章目录 概要主要贡献内容概述实验小结 概要 论文地址:https://arxiv.org/pdf/2312.00534.pdf 路沿检测在自动驾驶中扮演着重要的角色,因为它能够帮助车辆感知道可行驶区域和不可行驶区域。为了开发和验证自动驾驶功能,标注的数据是必不可…

ansible的控制语句

本章内容主要介绍 playbook 中的控制语句 使用when判断语句block-rescue判断循环语句 一个play中可以包含多个task,如果不想所有的task全部执行,可以设置只有满足某个条件才执行这个task,不满足条件则不执行此task。本章主要讲解when 和 blo…

婚庆婚礼策划服务网站建设的效果如何

品牌效应越来越重要,婚庆行业在多年的发展下,部分区域内也跑出了头部品牌,连锁门店也开了很多家,无论新品牌还是老品牌在新的区域开店总归少不了线上线下的宣传,虽然几乎每个人都会接触婚庆服务,但因为市场…

【并发编程篇】源码分析,手动创建线程池

文章目录 🛸前言🌹Executors的三大方法 🍔简述线程池🎆手动创建线程池⭐源码分析✨代码实现,手动创建线程池🎈CallerRunsPolicy()🎈AbortPolicy()🎈DiscardPolicy()🎈Dis…

1.倒排索引 2.逻辑斯提回归算法

1.倒排索引 https://help.aliyun.com/zh/open-search/retrieval-engine-edition/introduction-to-inverted-indexes 倒排索引(Inverted Index)是一种数据结构,用于快速查找包含某个特定词或词语的文档。它主要用于全文搜索引擎等应用&#…

c#委托学习笔记1

委托三步骤 第一步:定义委托 //第一步:1 声明委托(定义委托) //对于声明委托的解释如下: //解释a:函数指针 //解释b:委托就是定义函数的形状(形态) // 即:返回值类型&#x…

代码随想录刷题题Day21

刷题的第二十一天,希望自己能够不断坚持下去,迎来蜕变。😀😀😀 刷题语言:C Day21 任务 ● 216.组合总和III ● 17.电话号码的字母组合 1 组合总和III 216.组合总和III 思路: 在[1,2,3,4,5,6,…

数据孤岛:一场数据的独立战争

在当今数字化的时代,数据已成为企业和组织最宝贵的资产之一。然而,尽管数据的价值被广泛认可,但数据的分散和孤立问题却仍然存在,这就是所谓的数据孤岛。本文将重点分析什么是数据孤岛、数据孤岛的危害以及解决数据孤岛的传统和创…

C语言课程设计_运动会管理系统

本次课程设计利用《C语言程序设计》课程中所学到的编程知识和编程技巧,完成具有一定难度和工作量的程序设计题目,帮助学生掌握编程、调试的基本技能,独立完成所布置的任务。 要求 1、对系统进行功能需求分析 2、设计合理的数据结构和系统框…

分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测

分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测 目录 分类预测 | Matlab实现MTF-CNN-Mutilhead-Attention基于马尔可夫转移场-卷积神经网络融合多头注意力多特征数据分类预测分类效果基本描述程序设计参考…

HarmonyOS4.0系统性深入开发03UIAbility组件详解(中)

UIAbility组件基本用法 UIAbility组件的基本用法包括:指定UIAbility的启动页面以及获取UIAbility的上下文UIAbilityContext。 指定UIAbility的启动页面 应用中的UIAbility在启动过程中,需要指定启动页面,否则应用启动后会因为没有默认加载…

2024华为OD机试真题指南宝典—持续更新(JAVAPythonC++JS)【彻底搞懂算法和数据结构—算法之翼】

PC端可直接搜索关键词 快捷键:CtrlF 年份关键字、题目关键字等等 注意看本文目录-快速了解本专栏 文章目录 🐱2024年华为OD机试真题(马上更新)🐹2023年华为OD机试真题(更新中)🐶新…

Python字符串处理全攻略(三):常用内置方法轻松掌握

目录 引言Python字符串常用内置方法str.index()功能介绍语法注意事项总结 str.startswith()功能介绍语法示例注意事项 str.expandtabs()功能介绍语法示例注意事项总结 str.splitlines()功能介绍语法示例注意事项总结 str.swapcase()功能介绍语法示例注意事项 结束语 引言 欢迎…

XUbuntu22.04之跨平台容器格式工具:MKVToolNix(二百零三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…