Java - GoF设计模式详解13(解释器模式)
作者:hangge | 2023-05-17 08:10
十三、解释器模式
1,基本介绍
(1)解释器模式(Interpreter ):给定一种语言,定义它的文法表示,并定义一个解释器,该解释器根据文法表示来解释语言中的句子。
(2)解释器模式通常用于处理简单的语言或脚本,解释器模式通常用于以下场景:
- 当需要实现一个简单的语言或脚本时,可以使用解释器模式。例如,可以使用解释器模式实现简单的表达式求值器,或者实现简单的脚本语言来控制游戏的流程。
- 当需要对输入的某种语言进行解析时,可以使用解释器模式。例如,可以使用解释器模式来实现 SQL 解析器,将 SQL 语句解析为数据库操作。
- 当需要对一个复杂的问题进行分解,并使用解释器来解决每个子问题时,可以使用解释器模式。例如,可以使用解释器模式来实现某种算法,将复杂的算法分解成若干个子问题,然后使用解释器来解决每个子问题。
(2)该模式中包含的角色及其职责如下:
- 抽象表达式(Abstract Expression):定义解释器的接口,约定解释器所包含的操作,比如 interpret() 方法。
- 终结符表达式(Terminal Expression):抽象表达式的子类,实现与文法中的终结符相关联的解释操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression):抽象表达式的子类,文法中的每条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或其他关键字,比如关系运算符和逻辑运算符,它有两个或多个终结符表达式组成。
- 环境(Context):存储解释器之外的一些全局信息。
2,使用样例
(1)我们使用解释器模式来实现一个计算器,该计算器能够解析算术表达式并计算结果。首先,我们需要定义一个抽象的表达式(Abstract Expression)类,它声明了一个抽象的解释操作:
// 抽象的表达式(Expression)类 public abstract class Expression { public abstract int interpret(); }
(2)然后,我们定义 1 个表示数字的终结符表达式(Terminal Expression)类:
// 表示数字的终结符表达式(Terminal Expression)类 public class NumberExpression extends Expression { private int number; public NumberExpression(int number) { this.number = number; } @Override public int interpret() { return number; } }
(3)接着,我们定义四个非终结符表达式(Nonterminal Expression)类,分别表示数字、加号、减号和乘号这四种语法元素。
- 下面是表示加法的非终结符表达式(Nonterminal Expression)类:
// 加法非终结符表达式 public class PlusExpression extends Expression { private Expression left; private Expression right; public PlusExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret() { return left.interpret() + right.interpret(); } }
- 下面是表示减法的非终结符表达式(Nonterminal Expression)类:
// 减法非终结符表达式 public class MinusExpression extends Expression { private Expression left; private Expression right; public MinusExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret() { return left.interpret() - right.interpret(); } }
- 下面是表示乘法的非终结符表达式(Nonterminal Expression)类:
// 乘法非终结符表达式 public class MultiplyExpression extends 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(); } }
- 下面是表示除法的非终结符表达式(Nonterminal Expression)类:
// 除法非终结符表达式 public class DivisionExpression extends Expression { private Expression left; private Expression right; public DivisionExpression(Expression left, Expression right) { this.left = left; this.right = right; } @Override public int interpret() { return left.interpret() / right.interpret(); } }
(4)最后我们可以使用以下代码来测试计算器的功能。我们定义了一个包含加减乘除各种运算的表达式,计算器将解析并计算该表达式的值,最终输出 30。
public class Test { @SneakyThrows public static void main(String[] args) { // (10-5)*(1+10/2) Expression expression = new MultiplyExpression( new MinusExpression(new NumberExpression(10), new NumberExpression(5)), new PlusExpression( new NumberExpression(1), new DivisionExpression(new NumberExpression(10), new NumberExpression(2))) ); int result = expression.interpret(); System.out.println(result); // 输出 30 } }
附一:EL 表达式中的解释器模式
(1)Java 中的解释器模式在 javax.el 包中实现。javax.el 包提供了一个表达式语言(Expression Language,简称 EL),可以在 Java 中使用简单的语法来表示各种操作。例如,我们可以使用 EL 表达式来访问 Java 对象的属性、调用方法,以及进行条件判断和循环操作。
(2)在下面的代码中,我们使用 ELProcessor 类来解析 EL 表达式。ELProcessor 类是一个解释器,它能够将 EL 表达式解析为 Java 的运算结果。
public class Test { public static void main(String[] args) { ELProcessor el = new ELProcessor(); // 数值计算 long result = (long)el.eval("1 + 2 * 3"); System.out.println(result); // prints 7 // 逻辑运算 boolean condition = (boolean)el.eval("true && false"); System.out.println(condition); // prints false // 字符串拼接 String hello = (String)el.eval("'Hello, '.concat('World!')"); System.out.println(hello); // prints "Hello, World!" // bean访问 Map<String, String> map = new HashMap<>(); map.put("name", "航歌"); map.put("age", "100"); el.defineBean("bean", map); String name = (String)el.eval("bean.name"); System.out.println(name); // prints "航歌!" } }
(3)EL 表达式在 Java Web 应用程序中非常常见,可以在 JSP 文件、JSF 页面和其他类型的模板文件中使用。例如,我们可以在 JSP 文件中使用 EL 表达式来访问 JavaBean 的属性、调用方法,并将结果嵌入到 HTML 文档中。比如下面的 JSP 文件中,我们使用了 EL 表达式 ${bean.greeting()} 来调用 JavaBean 的 greeting() 方法,并将结果嵌入到 HTML 文档中。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <title>EL Example</title> </head> <body> <h1>EL Example</h1> <p>Greeting: ${bean.greeting()}</p> </body> </html>
附二:Spring 中的解释器模式
(1)Spring 框架中 SpelExpressionParser 使用到了解释器模式。Spring Expression Language(SpEL)是一种强大的表达式语言,它可以用于在运行时计算表达式的值。SpEL 主要用于在 Spring 框架中的各种地方,如 XML 配置文件和注解中,提供灵活的表达式语言支持。(2)SpEL 使用类似于 Java 的表达式语法,包括运算符、方法调用和访问对象属性等。它还提供了一些额外的功能,如访问上下文对象、调用静态方法和实例化对象等。下面是一些 SpEL 示例:
- 计算数学表达式:2 + 3 * 5
- 调用方法:'Hello, World!'.substring(6)
- 访问对象属性:person.name
- 调用静态方法:T(java.lang.Math).PI
- 实例化对象:new com.example.Person('John', 'Doe')
public class Test { public static void main(String[] args) { SpelExpressionParser parser = new SpelExpressionParser(); // 计算数学表达式:2 + 3 * 5 Expression expression = parser.parseExpression("2+3*5"); int result1 = (Integer) expression.getValue(); System.out.println(result1); //17 // 调用方法:'Hello, World!'.substring(3) expression = parser.parseExpression("'Hello, World!'.substring(3)"); String result2 = (String) expression.getValue(); System.out.println(result2); //lo, World! } }
(3)SpEL 也支持使用 #{} 语法在 XML 配置文件中使用表达式,例如在下面的例子中,SpEL 会在运行时计算表达式 systemProperties.userName 的值,并将结果赋值给 exampleBean 的 name 属性。
<bean id="exampleBean" class="com.example.ExampleBean"> <property name="name" value="#{systemProperties.userName}" /> </bean>
(4)SpEL 还可以用于 Spring 注解中,例如在下面的例子中,SpEL 会在运行时计算表达式 systemProperties.userName 的值,并将结果赋值给注解所修饰的字段 name。
@Value("#{systemProperties.userName}") private String name;
(5)另外,SpEL 还提供了一些特殊的函数,如:
- T() 函数用于指定类型,例如 T(java.lang.Math).PI 表示访问 java.lang.Math 类的静态字段 PI。
- null 函数用于返回 null 值,例如 null() 表示返回 null。
- literal() 函数用于将字符串解析为相应的类型,例如 literal('1') 会解析为整数 1。
(6)SpEL 还支持一些常用的运算符,包括算术运算符、比较运算符、逻辑运算符、三元运算符等。例如,下面是一些算术运算符的示例:
- + 加法运算符
- - 减法运算符
- * 乘法运算符
- / 除法运算符
- % 取模运算符
(7)总之,SpEL 是一种强大的表达式语言,可以用于在运行时计算表达式的值,并且可以在 Spring 框架的各种地方使用。它提供了类似于 Java 的表达式语法,并支持调用方法、访问对象属性、调用静态方法和实例化对象等功能。
全部评论(0)