解释器模式原理剖析和Spring中的应用

news2024/9/24 17:39:40

解释器模式原理剖析和Spring中的应用

解释器模式 是一种行为型设计模式,它定义了一种语言的文法表示,并提供了一个解释器来处理该文法的表达式。解释器模式可以用于构建语法解释器,例如计算器、简单编程语言的解释器等。

核心思想

解释器模式可以根据语言的文法定义多个表达式类,这些类通过组合和解释可以解析复杂的语言结构。它特别适合用于处理复杂表达式规则引擎,如数学表达式计算、正则表达式解析、脚本语言解释器等。

解释器模式的 UML 类图

在这里插入图片描述

角色说明:

  1. Expression(抽象表达式)
    • 抽象类或接口,定义了解释表达式的方法 interpret(),所有具体表达式类都实现该接口。
  2. TerminalExpression(终结符表达式)
    • 具体表达式类,用于解释最小的语法单元,如常量或变量。
  3. NonTerminalExpression(非终结符表达式,如 OrExpression、AndExpression)
    • 复杂表达式类,用于组合其他表达式,并定义复杂的解释操作(如逻辑运算、算术运算等)。

生动案例:简单规则引擎

场景描述

假设我们要设计一个规则引擎,用于处理用户输入的条件。条件表达式由多个规则组成,并且支持**“与”(AND)“或”(OR)**操作。具体规则包括判断输入的字符串是否包含某个单词。

例如:

  • 用户输入:“apple and orange”
  • 规则表达式:“包含’apple’ AND 包含’orange’”

通过解释器模式,我们可以设计一个系统来解析和执行这些规则。

代码实现:简单规则引擎

Step 1: 定义表达式接口

Expression 接口定义了 interpret() 方法,所有具体的表达式类都将实现该方法。

// 抽象表达式接口
public interface Expression {
    boolean interpret(String context);
}

Step 2: 实现终结符表达式

TerminalExpression 负责解释最基本的表达式,它判断一个字符串中是否包含指定的单词。

// 终结符表达式:判断字符串中是否包含某个单词
public class TerminalExpression implements Expression {
    private String word;

    public TerminalExpression(String word) {
        this.word = word;
    }

    @Override
    public boolean interpret(String context) {
        return context.contains(word);
    }
}

Step 3: 实现非终结符表达式

非终结符表达式 OrExpressionAndExpression 组合多个子表达式,用于处理更复杂的逻辑表达式。

OrExpression

// 非终结符表达式:OR 操作
public class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

AndExpression

// 非终结符表达式:AND 操作
public class AndExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public AndExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) && expr2.interpret(context);
    }
}

Step 4: 测试解释器模式

创建一些表达式并测试它们的解析逻辑。

public class InterpreterPatternDemo {

    // 构建规则:"apple OR orange"
    public static Expression getOrExpression() {
        Expression apple = new TerminalExpression("apple");
        Expression orange = new TerminalExpression("orange");
        return new OrExpression(apple, orange);
    }

    // 构建规则:"apple AND orange"
    public static Expression getAndExpression() {
        Expression apple = new TerminalExpression("apple");
        Expression orange = new TerminalExpression("orange");
        return new AndExpression(apple, orange);
    }

    public static void main(String[] args) {
        Expression orExpression = getOrExpression();
        Expression andExpression = getAndExpression();

        String test1 = "I like apple";
        String test2 = "I like orange";
        String test3 = "I like apple and orange";
        String test4 = "I like banana";

        System.out.println("Test1 (apple OR orange): " + orExpression.interpret(test1));
        System.out.println("Test2 (apple OR orange): " + orExpression.interpret(test2));
        System.out.println("Test3 (apple AND orange): " + andExpression.interpret(test3));
        System.out.println("Test4 (apple AND orange): " + andExpression.interpret(test4));
    }
}

输出结果

Test1 (apple OR orange): true
Test2 (apple OR orange): true
Test3 (apple AND orange): true
Test4 (apple AND orange): false

解释器模式在 Spring 框架中的应用剖析

解释器模式 在 Spring 框架中的应用并不像某些行为型模式(如策略模式、工厂模式)那样直接、明显,然而在一些高级功能或组件的实现中,解释器模式的思想仍然被应用到了。尤其是在需要处理表达式、规则解析或动态解析配置的场景中。

以下是解释器模式在 Spring 框架 中的几个重要应用场景:

1. Spring Expression Language (SpEL)

场景描述:

Spring 提供了一种强大的表达式语言——SpEL,它可以在运行时解析和求值表达式。这种语言的设计和实现思想与解释器模式非常类似。通过解释器模式,Spring 能够解析复杂的表达式,支持调用方法、访问对象属性、执行逻辑运算等功能。

SpEL 使用示例:
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

public class SpELDemo {

    public static void main(String[] args) {
        ExpressionParser parser = new SpelExpressionParser();

        // 解析并求值表达式
        Expression exp = parser.parseExpression("'Hello' + ' World'");
        String message = exp.getValue(String.class);
        System.out.println(message); // 输出:Hello World

        // 访问对象属性
        Person person = new Person("John", 30);
        StandardEvaluationContext context = new StandardEvaluationContext(person);
        String name = parser.parseExpression("name").getValue(context, String.class);
        System.out.println(name); // 输出:John
    }

    static class Person {
        public String name;
        public int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
}

解释

  • SpEL 是典型的解释器模式:用户可以定义表达式,而 SpEL 解析器会根据表达式的结构生成相应的解释器并执行它。这就像是解释器模式中的 TerminalExpressionNonTerminalExpression,SpEL 可以根据表达式中的操作符和操作数构建语法树,并对其进行解析和求值。
SpEL 工作原理:
  1. 解析表达式ExpressionParser 负责解析表达式字符串,生成相应的表达式对象。
  2. 生成解释器:解析器通过生成解释器类(类似于解释器模式中的 Expression),该类实现对表达式中每个操作符的解释。
  3. 求值:表达式对象通过调用 getValue() 方法执行解析和求值操作。
SpEL 的架构角色:
  • ExpressionParser:充当解释器模式中的 Context,负责管理表达式的解析和执行。
  • Expression:是解释器模式中的 AbstractExpression,负责定义表达式的抽象求值接口。
  • StandardEvaluationContext:类似于上下文环境,提供解析表达式时的环境变量。

2. @Value 注解中的表达式

在 Spring 中,使用 @Value 注解时可以结合 SpEL 表达式,动态解析 Bean 的属性值。这里用到的 SpEL 解析过程背后也是基于解释器模式。

示例

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class ConfigBean {

    @Value("#{2 + 3}")
    private int sum;

    @Value("#{configBean.sum * 2}")
    private int doubleSum;

    public int getSum() {
        return sum;
    }

    public int getDoubleSum() {
        return doubleSum;
    }
}

解释

  • @Value 注解中的表达式是在运行时解析的,它利用 SpEL 表达式解释器动态计算值。这些表达式解析的背后是解释器模式,Spring 在启动时解析表达式,生成解释器实例并求值。
  • 该模式允许开发者使用表达式来计算 Bean 属性值、访问其他 Bean 的属性或方法,并动态地将其注入到当前 Bean 中。

3.Spring AOP (Aspect-Oriented Programming)

Spring 的 **AOP(面向切面编程)**虽然不是直接使用解释器模式,但它在动态代理和切点表达式的解析过程中,采用了类似于解释器模式的机制。

AOP 中的表达式解析

  • 在定义切面时,开发者可以使用表达式来定义切点(@Pointcut)。Spring 在运行时会解析这些表达式,决定在哪些地方应用切面逻辑。

示例

@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    @Before("serviceLayer()")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Executing method: " + joinPoint.getSignature());
    }
}

解释

  • @Pointcut 中的 execution 表达式在运行时由 Spring AOP 框架解析,决定哪些方法会被拦截。
  • Spring AOP 背后采用了类似于解释器模式的机制来解析切点表达式,并动态应用横切关注点。

AOP 中的角色映射

  • @Pointcut 表达式:作为抽象表达式,描述了要执行的切面逻辑。
  • Spring AOP 框架:类似于解释器模式中的上下文,负责解析和执行切面表达式。

4.Spring 中的 EL 表达式

Spring 的配置文件中支持使用 表达式语言(EL),例如可以在 XML 配置中通过 SpEL 表达式动态计算或引用属性

<bean id="exampleBean" class="com.example.MyBean">
    <property name="sum" value="#{2 + 3}" />
</bean>

解释

  • Spring 通过解释器模式动态解析表达式并计算出结果。在配置文件加载时,Spring 会调用 SpEL 解释器,解析表达式并将结果注入到 Bean 属性中。

总结

  1. **扩展性强:**可以通过增加新的表达式类来扩展解释器,适合构建可扩展的文法解析系统。
  2. **易于理解和调试:**由于每个表达式类只负责一个小的功能,解释器模式的结构非常清晰,易于理解和测试。
  3. 性能问题:解释器模式在处理复杂的表达式时,可能会产生大量的对象,增加内存开销,并且计算过程可能较慢。
  4. 类的数量增加:对于每种语法规则或操作符,都会有一个对应的表达式类,可能导致类的数量急剧增加。

应用场景

  1. 数学表达式求值
    • 解释器模式非常适合用于实现数学表达式求值,如计算器的四则运算。
  2. 规则引擎
    • 解释器模式可用于构建规则引擎,帮助解析并执行复杂的业务规则。
  3. 脚本语言解释器
    • 解释器模式可以用于构建简单的脚本语言解释器,帮助解析并执行用户输入的命令或脚本。
  4. 正则表达式解析
    • 解释器模式可以应用于正则表达式的解析和匹配。

解释器模式 提供了一种灵活的方式来处理复杂的语法结构和表达式。通过定义终结符和非终结符表达式,解释器模式可以轻松地解析和计算复杂的表达式,如我们在例子中实现的四则运算解释器。通过递归组合表达式,系统能够处理复杂的逻辑和运算。

在现实世界中,解释器模式常用于数学表达式求值规则引擎脚本语言解释器等场景,它能让代码更具扩展性,并且容易理解和维护。

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

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

相关文章

成功使用DDNS动态域名访问我的群晖NAS(TP-link路由器)

当NAS设备部署在动态IP环境中&#xff08;如家庭或小型办公室宽带&#xff09;&#xff0c;远程访问常常受到IP地址频繁变动的困扰。为了解决这一问题&#xff0c;结合神卓互联NAS公网助手提供的DDNS&#xff08;动态域名服务&#xff09;功能&#xff0c;我们可以轻松实现通过…

蓝牙、WiFi、2.4G、Zigbee、LoRa、NB-IoT的区别与应用场景

在现代科技的推动下&#xff0c;无线通信技术已经成为我们生活中不可或缺的一部分。从智能家居到工业自动化&#xff0c;从远程监控到环境传感&#xff0c;每一种技术都有其独特的优势和应用场景。今天&#xff0c;我们将深入探讨六种主流的无线通信技术——蓝牙、WiFi、2.4G、…

基于vue框架的大参林药品信息管理系统的设计与实现8b4gt(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,药品分类,药品信息,医生 开题报告内容 基于Vue框架的大参林药品信息管理系统的设计与实现开题报告 一、引言 随着医疗健康行业的快速发展和信息化浪潮的推进&#xff0c;药品信息管理已成为提升医疗服务效率、保障患者用药安全、…

Activiti7《第九式:破气式》——流畅驱动工作流进程。面试题大全

冲冲冲&#xff01;开干 这篇文章将分为九个篇章&#xff0c;带你逐步掌握工作流的核心知识。“破气式”&#xff0c;代表着工作流中的 无形之力&#xff0c;它是贯穿整个流程的 关键驱动 不知不觉已经到了独孤九剑最后一式了&#xff0c;我相信到这里之后各位都已经出神入化…

状态模式原理剖析

《状态模式原理剖析》 状态模式&#xff08;State Pattern&#xff09; 是一种行为设计模式&#xff0c;它允许对象在其内部状态改变时改变其行为。换句话说&#xff0c;当对象状态发生变化时&#xff0c;它的行为也会随之变化。 核心思想&#xff1a; 状态模式将对象的不同状…

爬虫逆向学习(七):补环境动态生成某数四代后缀MmEwMD

声明&#xff1a;本篇文章内容是整理并分享在学习网上各位大佬的优秀知识后的实战与踩坑记录 前言 这篇文章主要是研究如何动态生成后缀参数MmEwMD的&#xff0c;它是在文章爬虫逆向学习(六)&#xff1a;补环境过某数四代的基础上进行研究的&#xff0c;代码也是在它基础上增…

华为HarmonyOS灵活高效的消息推送服务(Push Kit) -- 10 推送实况窗消息

场景介绍 实况窗是一种帮助用户聚焦正在进行的任务&#xff0c;方便快速查看和即时处理的通知形态。有关实况窗简介、权限申请、开放场景、设计规范等说明&#xff0c;请参见Live View Kit简介。 通过Push Kit发送的实况窗消息支持三种操作类型&#xff0c;分别是&#xff1a…

【全新课程】正点原子《基于GD32 ARM32单片机项目实战入门》培训课程上线!

正点原子《ESP32物联网项目实战》全新培训课程上线啦&#xff01;正点原子工程师手把手教你学&#xff01;彻底解决ARM32单片机项目入门难的问题&#xff01; 一、课程介绍 本课程专为ARM32单片机的入门学习者设计&#xff0c;涵盖了环境搭建、编程软件使用、模块基础驱动和多…

矩阵的逆怎么算?逆矩阵公式来了(附逆矩阵计算器)

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4da; 在线性代数中&#xff0c;逆矩阵是一个非常重要的概念。一个方阵如果存在逆矩阵&#xff0c;意味着该矩阵是可逆的&#xff0c;或者说是非奇异的。逆矩阵在解决线性方程组、计算矩阵的方根等方面有着广泛的应…

利用Accelerate()进行pytorch的多GPU加速

简介 官方Github&#xff1a;https://github.com/huggingface/accelerate Accelerate 是为喜欢编写PyTorch模型的训练循环但不愿意编写和维护使用多GPU/TPU/fp16所需的样板代码的PyTorch用户创建的。 它可以仅加速与多 GPU/TPU/fp16 相关的样板代码&#xff0c;并保持其余代…

Pyspark dataframe基本内置方法(5)

文章目录 Pyspark sql DataFrame相关文章toDF 设置新列名toJSON row对象转换json字符串toLocallterator 获取迭代器toPandas 转换python dataframetransform dataframe转换union unionALL 并集不去重&#xff08;按列顺序&#xff09;unionByName 并集不去重&#xff08;按列名…

jenkins声明式流水线语法详解

最基本的语法包含 pipeline&#xff1a;所有有效的声明式流水线必须包含在一个 pipeline 块中stages&#xff1a;包含一系列一个或多个stage指令stage&#xff1a;stage包含在stages中进行&#xff0c;比如某个阶段steps&#xff1a;在阶段中具体得执行操作&#xff0c;一个或…

提升工作效率神器

这五款软件让你事半功倍 在当今快节奏的社会中&#xff0c;提高工作效率成为了每个人追求的目标。而在这个数字化时代&#xff0c;选择对的软件工具无疑是提高效率的关键。今天&#xff0c;我为大家推荐五款优秀的工作效率软件&#xff0c;帮助你在工作中事半功倍。 1、亿可达…

15个 Jenkins 面试题

Jenkins 已成为持续集成和持续部署 (CI/CD) 流程中使用最广泛的自动化服务器之一。凭借其强大的功能和广泛的插件生态系统&#xff0c;Jenkins 已成为全球软件开发团队的首选工具。如果您正在准备 Jenkins 面试&#xff0c;那么精通其概念、架构和最佳实践至关重要。 为了帮助…

1.3 MySql的用户管理

一、下载Mysql客户端 下载navicat:Navicat 中国 | 支持 MySQL、Redis、MariaDB、MongoDB、SQL Server、SQLite、Oracle 和 PostgreSQL 的数据库管理 二、安装Navicat 三、创建数据库 创建一个数据库的连接吧&#xff0c;因为这个界面儿是图形界面儿&#xff0c;所以我们创建…

深入分析MySQL事务日志-Redo Log日志

文章目录 事务日志-Redo Log2.1 Redo Log2.1.1 Redo Log与持久性2.1.2 Redo Log的工作原理2.1.3 Redo Log的落盘策略2.1.4 Redo Log的系统参数 事务日志-Redo Log 事务的隔离性是通过锁实现&#xff0c;而事务的原子性、和持久性则是通过事务日志实现。在MySQL中&#xff0c;事…

【吉林大学编译原理题库】正则表达式的书写

1. 2. 选A 3. 没啥好说的&#xff0c;按意思写就行&#xff1a; 4. &#xfeff;5.设字母表S{0,1}&#xff0c;写正则表达式表示所有偶数个0和偶数个1组成的字符串。 6. 设字母表S{0,1}&#xff0c;写正则表达式表示所有偶数个0和奇数个1组成的字符串。&#xff08;提示&am…

Token usage of Content Filtered messages in Azure OpenAI Services

题意&#xff1a;在Azure OpenAI服务中&#xff0c;内容过滤消息的令牌使用 问题背景&#xff1a; When sending a message to a chat via GetChatCompletions as a response, I get a RequestFailedException. In the exception, I get an answer for which category content…

2-101基于matlab的频带方差端点检测

基于matlab的频带方差端点检测&#xff0c;噪声频谱中&#xff0c;各频带之间变化很平缓&#xff0c;语音各频带之间变化较激烈。据此特征&#xff0c;语音和噪声就极易区分。计算短时频带方差&#xff0c;实质就是计算某一帧信号的各频带能量之间的方差。这种以短时频带方差作…

揭秘MySQL主从复制:打造高可用性与数据冗余的强效引擎

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言&#…