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

news2025/7/19 17:54:12

简介

解释器模式属于行为型模式。它是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。是一种按照规定的语法进行解析的模式

编译器可以将源码编译解释为机器码,让CPU能进行识别并运行。解释器模式的作用与编译器一样,都是将一些固定的语法进行解释,构建出一个解释句子的解释器

简单理解,解释器是一个简单语法分析工具,它可以识别句子语义,分离终结符号和非终结符号,提取出需要的信息,让我们能针对不同的信息做出相应的处理。其核心思想是识别文法,构建解释

简而言之,解释器模式就是对于一些固定文法构建一个解释句子的解释器

应用场景

  1. 一些重复出现的问题可以用一种简单的语言来进行表达;
  2. 一个简单语法需要解释的场景;

主要角色

解释器模式主要包含四种角色

  1. 抽象表达式(Expression)

负责定义一个解释方法interpret,交由具体子类进行具体解释

  1. 终结符表达式(TerminalExpression)

实现文法中与终结符有关的解释操作。文法中的每一个终结符都有一个具体终结表达式与之相对应

如公式R = R1 + R2,R1和R2就是终结符,对应的解析R1和R2的解释器就是终结表达式

通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1, R2)

  1. 非终结符表达式(NonterminalExpression)

实现文法中与非终结符有关的解释操作

文法中的每条规则都对应于一个非终结符表达式

非终结符表达式一般是文法中的运算符或者其他关键字,如公式R=R1+R2中,“+”就是非终结符,解析"+"的解释器就是一个非终结符表达式

非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式

  1. 上下文环境类(Context)

包含解释器之外的全局信息。它的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,给R1赋值100,给R2赋值200,这些信息需要存放到环境中

优缺点

优点:

  • 扩展性强:在解释器模式中由于语法是由很多类表示的,当语法规则更改时,只需修改相应的非终结符表达式即可;若扩展语法时,只需添加相应非终结符类即可;
  • 增加了新的解释表达式的方式;
  • 易于实现文法:解释器模式对应的文法应当是比较简单且易于实现的,过于复杂的语法并不适合使用解释器模式。

缺点:

  • 语法规则较复杂时,会引起类膨胀:解释器模式每个语法都要产生一个非终结符表达式当语法规则比较复杂时,就会产生大量的解释类,增加系统维护困难;
  • 执行效率比较低:解释器模式采用递归调用方法,每个非终结符表达式只关心与自关的表达式,每个表达式需要知道最终的结果,因此完整表达式的最终结果是通过从后往前递归调用的方式获取得到;当完整表达式层级较深时,解释效率下降,且出错时调试困难,因为递归迭代层级太深

基本使用

使用解释器模式解析数学表达式

1. 创建抽象表达式

创建一个抽象表达式接口,定义一个表达式解释方法,由具体子类进行具体解释

public interface IExpression {
    // 对表达式进行解释
    int interpret();
}

2. 创建终结符表达式

public abstract class TerminalExpression implements IExpression {
    protected IExpression a;
    protected IExpression b;

    public TerminalExpression(IExpression a, IExpression b) {
        this.a = a;
        this.b = b;
    }
}

3. 创建非终结符表达式

加操作

public class AddNonterminalExpression extends TerminalExpression {
    public AddNonterminalExpression(IExpression a, IExpression b) {
        super(a, b);
    }

    @Override
    public int interpret() {
        return this.a.interpret() + this.b.interpret();
    }
}

减操作

public class SubNonterminalExpression extends TerminalExpression {

    public SubNonterminalExpression(IExpression a, IExpression b) {
        super(a, b);
    }

    @Override
    public int interpret() {
        return this.a.interpret() - this.b.interpret();
    }
}

数字操作

public class NumNonterminalExpression implements IExpression {

    private int value;

    public NumNonterminalExpression(int value) {
        this.value = value;
    }

    @Override
    public int interpret() {
        return this.value;
    }
}

4. 创建上下文环境类

public class CalculatorContext {
    private final Stack<IExpression> stack = new Stack<>();

    public CalculatorContext(String expression) {
        this.parse(expression);
    }

    // 解释器表达式
    private void parse(String expression) {
        String[] elements = expression.split(" ");
        IExpression aExpr, bExpr;

        for (int i = 0, length = elements.length; i < length; i++) {
            String operator = elements[i];
            if (CalculatorContext.isOperator(operator)) {
                aExpr = this.stack.pop();
                System.out.println("出栈: " + aExpr.interpret());
                bExpr = new NumNonterminalExpression(Integer.parseInt(elements[++i]));
                TerminalExpression res = CalculatorContext.util(aExpr, bExpr, operator);
                this.stack.push(res);
                System.out.println("计算: " + aExpr.interpret() + operator + bExpr.interpret());
                System.out.println("计算结果: " + Objects.requireNonNull(res).interpret() + "入栈");
            } else {
                NumNonterminalExpression numNonterminalExpression = new NumNonterminalExpression(Integer.parseInt(elements[i]));
                this.stack.push(numNonterminalExpression);
                System.out.println("入栈: " + numNonterminalExpression.interpret());
            }
        }
    }

    // 计算结果
    public int calculate() {
        int interpret = this.stack.pop().interpret();
        System.out.println("计算结果:" + interpret + "出栈");
        return interpret;
    }

    public static TerminalExpression util(IExpression a, IExpression b, String symbol) {
        if ("+".equals(symbol)) {
            return new AddNonterminalExpression(a, b);
        } else if ("-".equals(symbol)) {
            return new SubNonterminalExpression(a, b);
        } else {
            return null;
        }
    }

    public static boolean isOperator(String symbol) {
        return ("+".equals(symbol) || "-".equals(symbol));
    }
}

5. 创建客户端

public class Client {
    public static void main(String[] args) {
        // 创建上下文对象进行解释
        CalculatorContext calculatorContext = new CalculatorContext("10 + 20");
        // 获取执行结果
        System.out.println("calculatorContext.calculate() = " + calculatorContext.calculate());

        CalculatorContext calculatorContext2 = new CalculatorContext("10 + 20 - 15");
        System.out.println("calculatorContext.calculate() = " + calculatorContext2.calculate());
    }
}

运行结果:
在这里插入图片描述

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

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

相关文章

C++调用matlab引擎画三维图

VS2012设置 项目–项目属性–配置属性–VC目录–包含目录 D:\MATLAB\R2016a\extern\include 项目–项目属性–配置属性–VC目录–库目录 D:\MATLAB\R2016a\extern\lib\win64\microsoft 添加依赖项有两种方法&#xff1a; 方法一&#xff1a;项目中设置 项目–项目属性–配置属…

一、线程相关概念

文章目录相关概念程序(program)进程线程单线程与多线程并发与并行相关概念 程序(program) 是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码。 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c…

基于注解方式Spring Security忽略拦截

文章目录1.Spring Security忽略拦截配置2.基于配置文件注入2.1.添加配置2.2.修改Spring Security配置类2.3. 测试3.基于注解的方式过滤接口3.1.添加注解3.2.获取所有使用了IgnoreWebSecurity注解的接口访问路径3.3.测试1.Spring Security忽略拦截配置 关于Spring Securite的使…

SDL学习

学习笔记&#xff1a;整合安全开发生命周期SDL的Devops工具链建设 分享思路&#xff1a;《SDL安全开发生命周期介绍》 1、什么是SDL&#xff1f; 2、为什么需要SDL&#xff1f; 3、DevSecOps实践&#xff08;SDLDevOps&#xff09; 【整合安全开发生命周期SDL的DevOps工具链建…

408 考研《操作系统》第三章第一节:内存

文章目录教程1. 内存的基础知识1.1什么是内存&#xff1f;有何作用&#xff1f;补充知识&#xff1a;几个常用的数量单位2. 进程的运行原理2.1 指令的工作原理2.2 逻辑地址vs物理地址2.3 从写程序到程序运行2.4 装入模块装入内存2.5 装入的三种方式2.5.1 ——绝对装入2.5.2 ——…

VR的内容荒漠,字节救不了

文|智能相对论 作者|Kinki 去年以来&#xff0c;“元宇宙”概念大火&#xff0c;掀起了新一轮的产业布局和科技博弈&#xff0c;脸书Facebook更直接改名Meta&#xff0c;展示其看好元宇宙未来的决心&#xff0c;国内大厂如腾讯、字节、阿里等&#xff0c;也在游戏、社交、硬件…

Macos安装和卸载第三方软件的正确方法

Mac第三方软件通常指的是非MacApp Store渠道下载安装的应用程序。在Mac电脑中有很多Mac系统内置的软件&#xff0c;但有些用户也喜欢安装一些第三方的软件来提高工作效率&#xff0c;那么我们如何正确的安装和卸载第三方软件呢&#xff1f;教程都在下面哦~ mac第三方软件安装方…

Fabric.js 使用图片遮盖画布(前景图)

本文简介 点赞 关注 收藏 学会了 在 《Fabric.js 使用纯色遮挡画布》 中讲到使用纯色的方式遮盖画布。如果你的常见需要使用图片来遮盖的话&#xff0c;fabric.js 也提供了相应的属性来配置。 相比起使用纯色遮盖画布&#xff0c;使用图片会更复杂。 因为图片本身是有尺寸…

【科研工具】一款好用的科研插件-easyScholar

0.概述1.安装2.功能显示SCI分区&#xff1a;定位优质的文献【看分区排名靠前的1-2区】选中英文按下t翻译&#xff0c;按下y隐藏翻译点击文献网址的图标跳转sci-hub下载0.概述 easyScholar是一款很好用的科研插件&#xff0c;可以显示会议期刊登记&#xff0c;支持轻量翻译&…

SAP OData 服务关于本地文件作为附件上传的一些错误消息

错误消息&#xff1a; {"error": {"code": "005056A509B11EE3AEB5819C07C69E2F","message": {"lang": "en","value": "The server is refusing to process the request because the entity has a…

单机模拟主从复制(一主三从)

引言 操作系统环境&#xff1a;Ubuntu 20.04 Redis版本&#xff1a;6.2.8 准备工作 官网下载 当前最新版本是7.0&#xff0c;我这里用的是6.0&#xff0c;下载 redis-6.2.8.tar.gz&#xff0c;拷贝到自己的虚拟机或者云服务器。 tar -zxvf redis-6.2.8.tar.gz 解压 cd redi…

【HAL库】STM32CubeMX开发----STM32F407----SPI实验

前言 本次实验以 STM32F407VET6 芯片为MCU&#xff0c;使用 25MHz 外部时钟源。 SPI 通信引脚 与 MCU引脚 对应关系如下&#xff1a; SPI接口GPIO端口CS(片选)PA4SCLK(时钟)PA5MISO(数据输入)PA6MOSI(数据输出)PA7 一、使用STM32CubeMX ---- 新建SPI实验工程 步骤1&#xff…

crypto-music is frequency(INS‘hAck CTF 2018)

比较有趣的一题&#xff0c;记录下来。 Music is frequency Passionated by the sound of a nursery rhyme, we decided to build a new way to send private messages. Find a way to decrypt our rsa private key to get your reward. Because we are pretty bad musicians, …

postgres 源码解析46 可见性映射表VM

简介 Postgres 为实现多版本并发控制技术&#xff0c;当事务删除或者更新元组时&#xff0c;并非从物理上进行删除&#xff0c;而是将其进行逻辑删除[具体实现通过设置元组头信息xmax/infomask等标志位信息],随着业务的累增&#xff0c;表会越来越膨胀&#xff0c;对于执行计划…

【QScrollBar | QSlider | QDial | QProgressBar | QLCDNumber】

【QScrollBar | QSlider | QDial | QProgressBar | QLCDNumber】【1】UI设计界面【QScrollBar | QSlider 函数学习】【2】setMinimum | setMaximum【3】setSingleStep【4】setPageStep【5】setValue【6】setSliderPosition【7】setTracking【8】setOrientation【9】setInverted…

C++ :类和对象:文件操作

前言&#xff1a; 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行结束&#xff0c;数据都会被释放。通过文件可以 将数据持久化&#xff0c;C 中对文件操作需要包含头文件 <fstream>。 文件类型分为两种&#xff1a; 1&#xff1a;文本文件&#xff1a;文件…

历时9个月重构iNeuOS工业互联网操作系统,打造工业领域的“Office”

目 录 1. 概述... 1 2. 整体介绍... 2 3. 主要功能简介... 5 1. 概述 历时9个月的时间&#xff0c;对iNeuOS工业互联网操作系统进行全面重构&#xff0c;发布内部测试版本。重构的主要目的&#xff1a;工程化的框架优化&#xff0c;更好的聚焦工业领…

35.前端笔记-CSS3-3D转换

1、3D的特点 进大远小物体后面遮挡不可见 x:右为正 y:下为正 z:屏幕外是正&#xff0c;往里是负 3D移动之translate transform:translateX(100px);//仅仅是x轴移动。px或百分比 transform:translateY(100px);//仅仅是y轴移动&#xff0c;px或百分比 transform:translateZ(1…

33页企业内容管理与应用建设整体解决方案

当前企业在采购管理上面临的主要问题总体应对思路利用数字化技术&#xff0c;推动企业采购管理效能与职能升级 基于互联网技术架构推出数字化采购管理平台&#xff0c;帮助企业构建采购过程与供应商管理的两大流程闭环&#xff0c;实现采购过程的在线化协同&#xff0c;进而提升…

华为云大数据BI解决方案,助力企业实现数字化转型

2022年1月12日&#xff0c;国务院印发了《“十四五”数字经济发展规划》&#xff0c;规划明确提出到2025年&#xff0c;数字经济核心产业增加值占国内生产总值比重达到10%。这一规划的出台&#xff0c;充分释放出加快发展数字经济的明确信号&#xff0c;为各行业进行数字化转型…