Java设计模式之行为型-解释器模式(UML类图+案例分析)

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析

五、总结


 

一、基础概念

解释器模式是指给定一个语言(表达式),来表示它的文法,并定义一个解释器,使用该解释器来解释语言中的句子(表达式),并得到结果。简单来说,解释器模式把要处理的问题条条框框地定义出来,然后挨个细致解释,适合一些重复性的问题求解。

所谓终结符,是指表达式中的最小单位,它不再包含其他更小的表达式,可以理解为表达式的“叶子”节点,例如在一个简单的表达式计算器中:

1、数字值(如123)就是一个终结符,数字解释器实现了对数字的解释操作。

2、变量名(如a)也可以看作是一个终结符,变量解释器实现获取变量的值。

非终结符需要通过组合包含的子表达式的结果进行解释,例如:

1、加法表达式包含左边和右边两个子表达式,通过组合两个子表达式的计算结果实现加法。

2、函数调用表达式包含函数名和参数表达式,需要调用函数并传入参数计算结果。

举个例子:"5 + 6",然后解析这个表达式,计算出结果11。

在这个例子中:

1、数字5和6是终结符,它们是表达式的基本元素,不再包含其他表达式。

2、加号是非终结符,它表示一个表达式,需要通过计算5和6才能得出值。

所以简单来说:

1、终结符是表达式的基本元素,不再含其他表达式。

2、非终结符表示一个表达式,包含其他表达式。

二、UML类图

三、角色设计

角色描述
抽象表达式角色定义解释器的接口,声明一个解释操作interpret()
终结符表达式角色实现抽象表达式接口,表示语法规则中的终结符
非终结符表达式角色实现抽象表达式接口,表示语法规则中的非终结符,可以包含终结符和非终结符
客户端角色建立解释器对象,并调用interpret()方法进行解释操作

四、案例分析

下面我们通过模拟一个算术表达式的运算过程来实现解释器模式。

大体的工作流程如下:

1、构建表达式语法树。

2、用递归解释器对语法树进行解释执行。

3、终结符表达式直接返回值,非终结符表达式通过组合运算达到计算功能。

4、客户端构建语法树并调用解释器执行,即完成了对表达式的解析和求值。

代码设计如下:

定义一个抽象表达式角色,并定义了解释操作接口interpret():

public interface Expression {

    int interpret();

}

定义AddExpression,SubtractExpression等,非终结符表达式角色,它们实现了对复合表达式的解释,通过组合包含的子表达式的解释结果进行解释:

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;
        }
    }
}

定义NumberExpression,终结符表达式角色,它实现了对终结符的解释,这里的终结符是数字,直接返回数字的值:

public class NumberExpression implements Expression {

    private int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return number;
    }
    
}

客户端角色,添加一个Interpreter类,来解析表达式字符串,构建抽象语法树,并调用interpret()方法:

public class Client {

    public static void main(String[] args) {
        Expression expression = new SubtractExpression(
                new AddExpression(new NumberExpression(5),
                        new MultiplyExpression(new NumberExpression(10), new NumberExpression(15))),
                new DivideExpression(new NumberExpression(5), new NumberExpression(5))
        );
        int result = expression.interpret();
        System.out.println("计算结果为:" + result);

    }
}

运行结果如下:

执行流程如下:

1、在客户端中,首先构建一个减法表达式SubtractExpression,它的左表达式是加法表达式AddExpression,右表达式是除法表达式DivideExpression

2、加法表达式AddExpression的左表达式是数字表达式NumberExpression(5),右表达式是乘法表达式MultiplyExpression

3、乘法表达式MultiplyExpression的左表达式是数字表达式NumberExpression(10),右表达式是数字表达式NumberExpression(15)

4、除法表达式DivideExpression的左表达式是数字表达式NumberExpression(5),右表达式是数字表达式NumberExpression(5)

5、这样就构建出了一个完整的表达式树。

6、然后调用这个减法表达式的interpret()方法进行解释执行。

7interpret()方法会递归调用子表达式的interpret()方法,终结于数字表达式的interpret()只返回数字的值。

8、这样整个表达式树就得到了解释执行,得到最终结果。

9、这里的执行顺序是:数字表达式->乘法表达式->加法表达式->除法表达式->减法表达式,逐步对表达式树进行解释,得到最终的值。

所以这个案例利用了解释器模式,定义了表达式接口,并为不同的表达式实现了interpret()方法,通过组合模式构建表达式树,然后递归解释执行以求值。 

五、总结

优点:

1、可扩展性好。新增解释表达式较为方便,符合开闭原则。

2、易于改变和扩展语法。比如增加新的运算符等。

3、将语法解释与执行分离,允许程序动态地定制,每个节点只需要处理自身逻辑。

4、各部分功能模块较为独立,有利于实现和维护。

5、使用递归解释方式简化了语法树的evaluate逻辑。

缺点

1、解释过程效率较低,递归调用开销较大。

2、类数量多,之间依赖关系复杂,导致系统较难理解。

3、语法树构建较为麻烦,需要客户端理解语法结构。

4、语法树的解析需要定义大量的类,不易管理。

5、语言扩展较难,需要更改多个表达式类。

6、错误处理不容易,需要增加额外处理。

7、调试过程较复杂。

应用场景:

1、语言解释器:用于解析和解释语言中的表达式,如编译器、解释器等。这个代码案例就展示了如何通过解释器模式解析算术表达式。

2、表达式求值:用于进行表达式求值,如正则表达式、数学表达式、逻辑表达式等的求值运算。

3、符号处理引擎:可用来进行数学符号、表达式的解析。

4、语法分析:可构建语法树,用来分析句子或表达式所遵循的语法规则。

5、业务规则解析:可定义业务规则语法,并进行解释执行,用来实现规则引擎。

6、格式转换器:可将一种格式转换为另一种格式。

符合的设计原则:

1、开闭原则(Open Closed Principle)

解释器模式中的解释器语法可以通过继承扩展,而无需修改原有解释器代码,符合开闭原则。

2、单一职责原则(Single Responsibility Principle)

解释器模式把语法解析的任务分发给不同的解释器类,每一个解释器只负责一小部分语法规则,符合单一职责原则。

3、组合复用原则(Composite Reuse Principle)

解释器模式中的解释器可以通过组合方式重用,符合组合复用原则。

4、接口隔离原则(Interface Segregation Principle)

解释器模式通过定义解释器接口将解析语法和解释执行分离,符合接口隔离原则。

5、依赖倒转原则(Dependence Inversion Principle)

解释器类都依赖一个抽象语法树而不是具体语法类,符合依赖倒转原则。

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

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

相关文章

小奇猫物语之产品经理篇(2)

小奇猫物语之产品经理篇(2) 喵喵提示:小奇的产品经理篇(2)来咯,预告一下,前面几篇主要是讲产品经理的思维模式以及怎样去从一个学生思维转变成一个能带领一个项目的产品经理思维,所…

CSDN发表文章的常用语法说明

CSDN常用语法说明 一、标题二、文本样式三、列表四、图片五、链接六、目录一级目录二级目录三级目录 七、表格八、注释九、自定义列表十、LaTeX 数学公式十一、插入甘特图十二、插入UML图十三、插入Mermaid流程图十五、插入Flowchart流程图十六、 插入类图十七、快捷键十八、脚…

macOS Sonoma 14beta 3 (23A5286i)第二个更新「附黑/白苹果镜像下载」

系统镜像下载: 系统介绍 黑果魏叔 7 月12 日消息,苹果今天发布 macOS Sonoma 14.0 Beta 3(内部版本号:23A5286i)第二个更新。 目前尚不清楚苹果为什么要发布 macOS Sonoma Beta 3 的第二个版本,但它可能…

WooCommerce适合企业电子商务吗?

目录 成功开展电子商务业务变得比以往任何时候都容易。市场上有几个现成的平台,完全有可能将一个初步的想法快速转变为在线贸易业务,并源源不断地收到订单。 什么是 WooCommerce? 为什么您应该考虑使用 WooCommerce 很灵活 重量轻且功…

家政服务小程序软件解决方案

家政服务小程序软件是近年来随着人们对家政服务需求的增长而逐渐兴起的一种数字化服务解决方案。通过小程序软件,用户可以轻松预约家政服务,包括保姆、月嫂、钟点工等,而且价格透明、服务规范,大大提高了用户对家政服务的满意度。…

C++ cin

cin 内容来自《C Primer》 cin使用>>运算符从输入流中抽取字符 int carrots;cin >> carrots;如下的例子&#xff0c;用户输入的字符串有空格 #include <iostream>int main() {using namespace std;const int ArSize 20;char name[ArSize]; //用户名char …

nodejs 下载地址 阿里云开源镜像站

nodejs 下载地址 阿里云开源镜像站 https://mirrors.aliyun.com/nodejs-release/ 我们下期见&#xff0c;拜拜&#xff01;

Vue3的watchEffect的妙用,与watch的区别

前言 在Vue3中&#xff0c;引入了Composition API&#xff0c;其中的watchEffect()函数是一个非常强大和灵活的工具&#xff0c;用于处理响应式数据的变化&#xff0c;使得项目更加弹性和灵活。它与watch有所不同&#xff0c;本文将介绍watchEffect()的定义、特点、与watch的区…

24 MFC文档串行化和单文档应用程序

文章目录 文档串行化全部代码 单文档应用程序搭建原理搭建框架Win32 过度到MFC 三部曲设置ID资源全部代码 单文档应用程序设置标题绘图 简单的管理系统部分代码 文档串行化 ui 设计 保存 void CfileDemoDlg::OnBnClickedBtnSave() {UpdateData();//CFile file(L"Demo.dat…

linux驱动开发:驱动开发框架,linux内核字符设备驱动开发过程

一、驱动框架 1.Linux内核模块和字符驱动的关系 模块是Linux进行组建管理的一种方式, 结构体:对设备的管理内核需要抽象出来一个结构体来描述设备所有的共性信息写驱动需要申请一个结构体并赋值(初始化),然后注册给内核让内核统一管理 驱动:由内核统一管理,所以驱动…

Flask_自定义flask的cmd命令

创建自定义命令 from flask import Flaskapp Flask(__name__)app.cli.command() def hello():"""命令说明写这里"""print("hello python")if __name__ __main__:app.run() 执行flask --help 可以在命令查看定义的命令 注意事项&a…

CDN技术(Content Delivery Network,内容分发网络)分布式网络架构(CND与P2P(Peer-to-Peer)区别)

文章目录 CDN是什么&#xff1f;CDN的优势CDN的应用1. 静态内容加速2. 动态内容加速3. 视频流媒体4. 软件分发5. 游戏加速6. 移动应用加速 CDN收费吗&#xff1f;CND与P2P区别什么是静态内容和动态内容&#xff1f; CDN是什么&#xff1f; CDN&#xff08;Content Delivery Ne…

设计模式大白话——工厂模式

文章目录 设计模式大白话——工厂模式1.1、简单工厂:1.2、工厂方法1.3、抽象工厂 设计模式大白话——工厂模式 1.1、简单工厂: 场景与思路 ​ 现在需要开一个 Pizza 店&#xff0c;Pizza 店可以生产各种口味的 Pizza ​ 既然要生产各种各样的 Pizza&#xff0c;那就会很容易想…

在新建环境下配置低版本opencv

我这边是要解决 python报错&#xff1a;AttributeError: ‘module’ object has no attribute xfeatures2d’的问题&#xff0c; xfeatures2d在新版本已经被取消&#xff0c;但是需要使用老版本的一个函数 确定opencv与python的版本对应关系 一般来说可以对照这个表 具体来说…

【Spring】Spring更简单的读取和存储对象---使用注解

目录 1.Spring的存储对象------存储Bean对象 1.前置工作&#xff0c;配置扫描路径 2.添加注解存储Bean对象 1.Controller&#xff08;控制器存储&#xff09; 2.service&#xff08;服务存储&#xff09; 3.Repository&#xff08;仓库存储&#xff09; 4.Component&…

Java面试突击

Java面向对象有哪些特征&#xff0c;如何应用 ​ 面向对象编程是利用类和对象编程的一种思想。万物可归类&#xff0c;类是对于世界事物的高度抽象 &#xff0c;不同的事物之间有不同的关系 &#xff0c;一个类自身与外界的封装关系&#xff0c;一个父类和子类的继承关系&…

手动下载composer项目放在vendor目录下并加载

比如添加easywechat。 说是手动&#xff0c;其实半手动。 到GitHub或gitee下载 1、下载后放在项目根目录下的vendor文件夹 2、在项目根目录的文件composer.json文件添加一段 "autoload": {"psr-4": {"EasyWeChat\\": "vendor/overtrue/wech…

HCIP第一课实验小练习

目录 题目&#xff1a;​编辑 第一步&#xff1a;地址规划&#xff08;子网划分&#xff09; 第二步&#xff1a;设计拓扑并规划地址配置 第三步&#xff1a;VLAN规划配置 LW1 LW2 第四步&#xff1a;网关配置 第五步&#xff1a;及静态路由配置 第六步防止成环 题目&…

计算机视觉和滤帧技术

01 什么是计算机视觉 进入主题之前&#xff0c;先聊聊计算机视觉。 计算机视觉是指利用摄像头和电脑识别、跟踪和测量目标&#xff0c;并进行图像处理&#xff0c;使其适合人眼观察或仪器检测。作为一个科学学科&#xff0c;计算机视觉模拟生物视觉&#xff0c;旨在实现图像和视…

郭东白的架构课学习笔笔记(1)

1.架构师的品质 自信和勇气&#xff08;正确的废话&#xff09;拥有战略意图&#xff0c;所谓战略意图&#xff0c;就是拥有与其资源和能力极不相称的雄心壮志。使用演绎法寻找架构原理&#xff0c;而不是归纳法。 2.如何提升自己的架构能力 向身边比自己厉害的优秀架构师或…