行为型模式 - 解释器模式

news2024/11/19 7:22:06

概述

如上图,设计一个软件用来进行加减计算。我们第一想法就是使用工具类,提供对应的加法和减法的工具方法。  

//用于两个整数相加
public static int add(int a,int b){
    return a + b;
}

//用于两个整数相加
public static int add(int a,int b,int c){
    return a + b + c;
}

//用于n个整数相加
public static int add(Integer ... arr) {
    int sum = 0;
    for (Integer i : arr) {
        sum += i;
    }
    return sum;
}

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

显然,现在需要一种翻译识别机器,能够解析由数字以及 + - 符号构成的合法的运算序列。如果把运算符和数字都看作节点的话,能够逐个节点的进行读取解析运算,这就是解释器模式的思维。

定义:

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

在解释器模式中,我们需要将待解决的问题,提取出规则,抽象为一种“语言”。比如加减法运算,规则为:由数值和+-符号组成的合法序列,“1+3-2” 就是这种语言的句子。

解释器就是要解析出来语句的含义。但是如何描述规则呢?

文法(语法)规则:

文法是用于描述语言的语法结构的形式规则。

expression ::= value | plus | minus
plus ::= expression ‘+’ expression   
minus ::= expression ‘-’ expression  
value ::= integer

注意: 这里的符号“::=”表示“定义为”的意思,竖线 | 表示或,左右的其中一个,引号内为字符本身,引号外为语法。

上面规则描述为 :

表达式可以是一个值,也可以是plus或者minus运算,而plus和minus又是由表达式结合运算符构成,值的类型为整型数。

抽象语法树:

在计算机科学中,抽象语法树(AbstractSyntaxTree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。

用树形来表示符合文法规则的句子。

 

结构

解释器模式包含以下主要角色。

  • 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。

  • 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。

  • 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。

  • 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。

  • 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。

案例实现

【例】设计实现加减法的软件

代码如下:  

//抽象角色AbstractExpression
public abstract class AbstractExpression {
    public abstract int interpret(Context context);
}

//终结符表达式角色
public class Value extends AbstractExpression {
    private int value;

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

    @Override
    public int interpret(Context context) {
        return value;
    }

    @Override
    public String toString() {
        return new Integer(value).toString();
    }
}

//非终结符表达式角色  加法表达式
public class Plus extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public Plus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) + right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}

///非终结符表达式角色 减法表达式
public class Minus extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;

    public Minus(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
        return left.interpret(context) - right.interpret(context);
    }

    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

//终结符表达式角色 变量表达式
public class Variable extends AbstractExpression {
    private String name;

    public Variable(String name) {
        this.name = name;
    }

    @Override
    public int interpret(Context ctx) {
        return ctx.getValue(this);
    }

    @Override
    public String toString() {
        return name;
    }
}

//环境类
public class Context {
    private Map<Variable, Integer> map = new HashMap<Variable, Integer>();

    public void assign(Variable var, Integer value) {
        map.put(var, value);
    }

    public int getValue(Variable var) {
        Integer value = map.get(var);
        return value;
    }
}

//测试类
public class Client {
    public static void main(String[] args) {
        Context context = new Context();

        Variable a = new Variable("a");
        Variable b = new Variable("b");
        Variable c = new Variable("c");
        Variable d = new Variable("d");
        Variable e = new Variable("e");
        //Value v = new Value(1);

        context.assign(a, 1);
        context.assign(b, 2);
        context.assign(c, 3);
        context.assign(d, 4);
        context.assign(e, 5);

        AbstractExpression expression = new Minus(new Plus(new Plus(new Plus(a, b), c), d), e);

        System.out.println(expression + "= " + expression.interpret(context));
    }
}

优缺点

1,优点:

  • 易于改变和扩展文法。

    由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。每一条文法规则都可以表示为一个类,因此可以方便地实现一个简单的语言。

  • 实现文法较为容易。

    在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂。

  • 增加新的解释表达式较为方便。

    如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合 "开闭原则"。

2,缺点:

  • 对于复杂文法难以维护。

    在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护。

  • 执行效率较低。

    由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。

使用场景

  • 当语言的文法较为简单,且执行效率不是关键问题时。

  • 当问题重复出现,且可以用一种简单的语言来进行表达时。

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

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

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

相关文章

玩转代码|JS实现中文字符串对utf-8的Base64编码的方法

目录 UTF-8 字符串编解码 解决方法 解析 utf8_to_b64 b64_to_utf8 弃用 unescape 和 escape 方法 原由 解决方法 Node.js 下的 Base64 编解码 Base64 编解码 Base64是一种使用64基的位置计数法。它使用2的最大次方来代表仅可打印的ASCII 字符。这使它可用来作为电子邮…

YOLOv2论文对比总结

1、高分辨率图片效果提升 2、Anchor 3、Loss函数 4、小目标友好

【文献分享】比目前最先进的模型轻30%!高效多机器人SLAM蒸馏描述符!

论文题目&#xff1a;Descriptor Distillation for Efficient Multi-Robot SLAM 中文题目&#xff1a;高效多机器人SLAM蒸馏描述符 作者&#xff1a;Xiyue Guo, Junjie Hu, Hujun Bao and Guofeng Zhang 作者机构&#xff1a;浙江大学CAD&CG国家重点实验室 香港中文大学…

Windows安装Redis(配置开机自启+配置密码)

Windows安装Redis 背景安装配置开机自启补充: 在Windows中配置jar自启动 设置密码暂时永久(推荐) 背景 Redis以其优异的性能备受青睐. 成为开发人员离不开的软件一直, 相信愿意点开观看此文的人DDDD 最近因为需要在Windows服务器上面搭建各种项目运行环境, 其中就包括Redis 因…

vue 实现课程表甘特图

1 封装 components <template><view style"padding-bottom: 100rpx;"><view class"header flex_sb"><div class"header_list flex" v-for"(item,index) in timeList" :key"item.value"><div&g…

CORS跨域资源共享漏洞

前置知识 跨域 域&#xff08;Domain&#xff09;是由三部分组成的标识&#xff1a;协议、域名和端口。 例如这两个ip就属于不同的域&#xff1a; http://example.com https://example.com 因为它们的协议不同&#xff08;一个是HTTP&#xff0c;另一个是HTTPS&#xff0…

2023百强县名单出炉!千亿县达54个

作为国民经济发展中的基本单元&#xff0c;县域经济发挥着重要作用。 赛迪顾问25日发布的《2023中国县域经济百强研究》&#xff08;下称“报告”&#xff09;显示&#xff0c;千亿县达54个&#xff0c;百强县前10名中江苏省独占6席。 在百强县前10名中&#xff0c;江苏省占席最…

Esp32_Arduino接入腾讯云笔记

ESP32是一款由乐鑫科技&#xff08;Espressif Systems&#xff09;推出的双核、低功耗、集成Wi-Fi和蓝牙的单芯片微控制器。它采用了Tensilica Xtensa LX6高性能处理器&#xff0c;具有大量的GPIO引脚、模数转换器、SPI、I2S、UART、PWM、I2C和SD卡接口等功能&#xff0c;可以满…

android 清除缓存方法

获得应用的存储信息 private void getAppStorageInfo(String packageName){StorageStatsManager storageStatsManager (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);StorageManager storageManager (StorageManager) context.getSystemS…

第二十一章 数据处理篇:imgaug

参考教程&#xff1a; https://imgaug.readthedocs.io/en/latest/source/jupyter_notebooks.html 文章目录 概述针对图片的增强基础使用样例base class: augment增强的组合sequentialsomeof和oneofsometimes 增强的种类 针对关键点的增强针对包围框的增强 概述 imgaug是一个使…

【深度学习】GPT-3

2020年5月&#xff0c;OpenAI在长达72页的论文《https://arxiv.org/pdf/2005.14165Language Models are Few-Shot Learners》中发布了GPT-3&#xff0c;共有1750亿参数量&#xff0c;需要700G的硬盘存储&#xff0c;(GPT-2有15亿个参数)&#xff0c;它比GPT-2有了极大的改进。根…

PX4常见解锁失败报错及解决方法

文章目录 一、Kill switch engagen二、电源检查CBRK_SUPPLY_CHK三、USB连接检查CBRK_USB_CHK四、安全开关检查CBRK_IO_SAFETY五、high Accelerometer bios六、high gyro bios七、compasss inconsistent八、GPS报错九、Accels inconsistent十、偏航角一直漂移十一、PREFLIGHT FA…

同步编程和异步编程的区别

我在这里用几个例子&#xff08;附带图文&#xff09;给你们讲解一下&#xff0c;具体区别。 第一个例子 一、同步 执行步骤&#xff1a; step1 》 step2 》step3 先打印 hello moon&#xff0c; 再打印图片&#xff0c; 等待图片打印完&#xff0c;再打印 hello Jupiter …

全国青少年信息素养大赛Scratch图形化编程_初赛_模拟一卷

全国青少年电子信息智能创新大赛Scratch图形化编程_初赛_模拟一卷 一、选择题 第 1 题 单选题 能让角色在整个舞台范围内的任意位置出现的程序是&#xff1f;&#xff08; &#xff09; A. B. C. D. 第 2 题 单选题 猫抓老鼠游戏的封面上有“开始”按钮和“游戏规则”两…

实战:Docker+Jenkins+Gitee构建CICD流水线

文章目录 前言Jenkins部署创建Jenkins docker-compose配置maven源启动Jenkins容器安装插件Gitee ssh公匙配置与测试项目提交 Jenkins创建流水线写在最后 前言 持续集成和持续交付一直是当下流行的开发运维方式&#xff0c;CICD省去了大量的运维时间&#xff0c;也能够提高开发…

Windows环境部署安装Chatglm2-6B-int4

chatglm2-6B是最近比较火爆的大模型&#xff0c;可以在消费级显卡上部署使用&#xff0c;适合学习。但是一般人也不一定有那么高的硬件配置&#xff0c;所以部署个int4版本应该是大多数人的最好选择。我就在家里部署起了int4版本的chatglm2-6B&#xff0c;记录一下免得忘了。 …

Docker资源限制

Docker资源限制 一、cpu资源控制1、 设置cpu使用率上限2、设置cpu资源占用比&#xff08;设置多个容器时才有效&#xff09;3、设置容器绑定指定的CPU 三、内存资源控制四、磁盘IO配额控制1、限制Block IO2、限制bps和iops进行限制 一、cpu资源控制 cgroups是一个非常强大的li…

VMware虚拟机无法自动获取IP地址的解决办法

安装好虚拟机后&#xff0c;网络是ok的&#xff0c;但是关机后&#xff0c;再次开启就不能用了。网上找了好多方法&#xff0c;都不管用&#xff0c;最后恢复默认设置搞定了&#xff0c;实在没办法的可以试一试

【致敬未来的攻城狮计划】第3期 作业汇总贴 + 获奖公布(文末荐书)

目录 一、写在前面 二、种子学员介绍 三、作业贴汇总 四、小小总结 五、获奖公布 六、学员有话说 七、特别致谢 八、友情荐书 一、写在前面 时间过得真快&#xff0c;距离 【致敬未来的攻城狮计划】第3期 的发起&#xff0c;已经过去有些时间了&#xff0c;让我们一起…

FileHub使用教程:Github Token获取步骤,使用快人一步

FileHub介绍 filehub是我开发的一个免费文件存储软件&#xff0c;可存万物。软件仓库&#xff1a;GitHub - Sjj1024/s-hub: 一个使用github作为资源存储的软件 软件下载地址&#xff1a;。有问题可以留言或者提Issue&#xff0c; 使用第一步&#xff1a;获取Github Token 使…