目录
解释器模式【Interpreter Pattern】,什么是解释器模式?作用?优缺点?应用场景?主要角色?
什么是解释器模式?
解释器模式(Interpreter Pattern)是一种行为型设计模式,用于定义一种语言的语法表示,并提供一个解释器来解析和执行这种语法。换句话说,解释器模式适用于为某种语言或表达式定义文法规则,并通过解析这些规则执行操作。
解释器模式的作用?
解析并执行语言或表达式:解释器模式的主要作用是为一种特定的领域语言或表达式提供解释的能力,使得系统能够根据定义的文法规则来解析并执行用户输入。
简化文法和解析过程:通过定义具体的解释器类来解析不同的语法结构,能够把复杂的语法解析任务模块化。
解释器模式的优缺点
优点
(1)易于扩展
可以很容易地通过增加新的解释器类来扩展文法,增加新的语法规则。
(2)灵活性高
适合处理一些复杂的、有规律的文法,尤其在需要频繁更改和扩展文法规则时。
(3)代码清晰
每个语法规则都可以通过类来表示,结构化清晰,便于维护。
缺点
(1)性能问题
如果文法非常复杂,解释器模式的实现会变得非常庞大,效率也会下降。对于复杂的语言,解释器模式不适用,可能会导致性能瓶颈。
(2)难以维护
当文法规则较多时,会导致大量的类和对象,使系统难以维护。
(3)扩展性受限
如果设计不当,随着语法复杂度增加,扩展可能变得不够灵活,容易引入错误。
解释器模式应用场景
(1)编译器或解释器开发
为特定语言开发解释器,解析并执行代码。例如,用于解析数学表达式的解释器。
(2)规则引擎
在业务规则系统中,可以通过解释器模式来定义和解析规则,例如判断某些条件是否满足特定业务需求。
(3)命令执行器
用于解析用户命令,并执行相应的操作,例如在脚本语言或游戏开发中。
(3)正则表达式引擎
解释正则表达式并解析字符串匹配的模式。
解释器模式的主要角色?
(1)抽象表达式(Abstract Expression)
解释器模式的核心接口或抽象类,定义了解释操作的接口,通常包含一个interpret()方法。所有具体的表达式类都需要实现或继承这个抽象表达式。
职责:定义表达式的解释方法,用于解析和处理表达式。
(2)终结符表达式(Terminal Expression)
处理最基本的元素的具体表达式类。终结符表达式通常是文法的最基本单元,例如:数字或常量。
职责:实现interpret()方法,用来处理具体的值或变量,在抽象语法树中不再有下级结构。例如:在数学表达式解析中,数字或变量是终结符表达式。
(3)非终结符表达式(Non-Terminal Expression)
由其他表达式(通常包括终结符和非终结符)构成的表达式。非终结符表达式通常是复合的操作,例如加法、乘法等。
职责:实现interpret()方法,递归调用其他表达式的interpret()方法来完成复杂表达式的求值。通常表示文法中的运算符或组合表达式。
(4)上下文(Context)
上下文对象存储解释器执行时需要的全局信息。例如:变量的定义、解释器的状态等。它为解释器提供外部的信息支持。
职责:提供解释器所需的输入,帮助维护状态,存储表达式求值时的一些必要信息(如变量的值)。
(5)客户端(Client)
客户端是使用解释器模式的用户,负责将特定的语言或表达式表示为抽象语法树,并通过调用解释器来处理或求值。
职责:构造抽象语法树(AST),组合终结符和非终结符表达式,并调用它们的interpret()方法来获得最终结果。
解释器模式角色关系
(1)抽象表达式:定义了解释的通用接口或抽象类,具体表达式类(终结符和非终结符表达式)实现了该接口。
(2)终结符表达式:负责处理基本的输入,而非终结符表达式通过递归组合其他表达式来处理复杂的输入。
(3)上下文:为解释提供支持信息,可能存储变量的值或外部数据。
(4)客户端:负责构建和使用解释器,最终获得表达式的结果。
解释器模式实现案例
以解析和计算简单的数学表达式(加法和乘法)为例,解释器会按照指定的语法规则执行表达式计算。
1、定义上下文(存储变量及其对应的值)
Context 类用于存储变量名与其对应的值。通过调用 setVariable(String name, int value),可以动态地设置变量的值。getVariable(String name) 方法用于在表达式解析时获取变量的值。
package com.uhhe.common.design.interpreter;
import java.util.HashMap;
import java.util.Map;
/**
* 上下文,存储变量及其对应的值
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:39
*/
public class Context {
private final Map<String, Integer> VARIABLE_MAP = new HashMap<>();
public void setVariable(String name, int value) {
VARIABLE_MAP.put(name, value);
}
public int getVariable(String name) {
return VARIABLE_MAP.get(name);
}
}
2、抽象表达式接口
是一个通用的接口,定义了一个方法interpret(Context context),表示执行解释操作。所有具体的表达式类都实现这个接口。接口的职责是定义解析和执行表达式的通用方法。
Context 参数可以从上下文中获取外部信息(例如:变量的值)。
package com.uhhe.common.design.interpreter;
/**
* 抽象表达式接口
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:39
*/
public interface Expression {
/**
* 解释
*
* @return 返回值
*/
int interpret(Context context);
}
3、终结符表达式类(处理具体数字)
NumberExpression类表示表达式中的具体数字。interpret()方法返回这个数字的值。这个类用来处理表达式中的具体数值,如: 3、5、2 等。
package com.uhhe.common.design.interpreter;
/**
* 终结符表达式类(处理具体数字)
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:40
*/
public class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret(Context context) {
return number;
}
}
4、终结符表达式类(处理变量)
VariableExpression 类用于处理变量。该类在 interpret() 方法中从上下文中获取变量的值。
package com.uhhe.common.design.interpreter;
/**
* 终结符表达式类(处理变量)
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:40
*/
public class VariableExpression implements Expression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public int interpret(Context context) {
return context.getVariable(name);
}
}
5、非终结符表达式类(加法运算)
接受两个 Expression 对象作为参数(左操作数和右操作数),并在 interpret() 方法中递归地对这两个操作数调用 interpret(),从而计算出加法或乘法的结果。
package com.uhhe.common.design.interpreter;
/**
* 非终结符表达式类(加法运算)
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:40
*/
public class AddExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public AddExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public int interpret(Context context) {
return leftExpression.interpret(context) + rightExpression.interpret(context);
}
}
6、非终结符表达式类(乘法运算)
与 AddExpression 类似
package com.uhhe.common.design.interpreter;
/**
* 非终结符表达式类(乘法运算)
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:41
*/
public class MultiplyExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public MultiplyExpression(Expression leftExpression, Expression rightExpression) {
this.leftExpression = leftExpression;
this.rightExpression = rightExpression;
}
@Override
public int interpret(Context context) {
return leftExpression.interpret(context) * rightExpression.interpret(context);
}
}
7、客户端代码,使用解释器模式
客户端代码负责构建整个表达式的结构(即抽象语法树)。
在示例中,构建了一个表达式 (3 + 5) * 2,这是通过组合多个 Expression 对象来实现的;最后,客户端调用 multiplyExpression.interpret() 解释并执行整个表达式,输出最终结果 16。
package com.uhhe.common.design.interpreter;
/**
* 客户端代码,使用解释器模式
*
* @author nizhihao
* @version 1.0.0
* @date 2024/9/8 16:41
*/
public class InterpreterPatternDemo {
public static void main(String[] args) {
// (3 + 5) * 2 的表达式
// 创建上下文,并设置变量的值
Context context = new Context();
context.setVariable("x", 3);
context.setVariable("y", 5);
context.setVariable("z", 2);
// 终结符表达式:表示数字和变量
Expression number1 = new VariableExpression("x"); // x = 3
Expression number2 = new VariableExpression("y"); // y = 5
Expression number3 = new VariableExpression("z"); // z = 2
// 非终结符表达式:x + y
Expression addExpression = new AddExpression(number1, number2);
// 非终结符表达式:(x + y) * z
Expression multiplyExpression = new MultiplyExpression(addExpression, number3);
// 解释表达式并输出结果
System.out.println("Result: " + multiplyExpression.interpret(context)); // 输出结果 16
}
}