23种设计模式——解释器模式(Interpreter Pattern)
✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式——解释器模式(Interpreter Pattern)
📚 ** ps ** :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。
目录
一. 背景
二. 介绍
三. 主要角色
四. 代码示例
五. 应用场景
六. 优缺点
七. 总结
一. 背景
解释器模式对于很多人可能会感到陌生。但编程学习者对于解释这个词语的理解,可能会想到Python,因为它是解释型语言,可能有人也会想到正则表达式,因为它是解释器模式应用的典型案例。下面,将会对解释器模式进行详细的解释。
二. 介绍
解释器模式是一种行为型设计模式,它能让你定义一种语言的语法,并提供一个解释器来处理该语法。这种模式适用于你需要解析和执行特定语言或表达式的场景。
解释器模式主要用于处理像正则表达式、SQL 查询语句或者自定义 DSL(领域特定语言)等结构化文本。它的核心思想是将每个语法规则表示为一个类,从而构建出一个抽象语法树(AST)来表示复杂的句子。
三. 主要角色
AbstractExpression(抽象表达式):声明一个抽象的解释操作接口
TerminalExpression(终结符表达式):实现与文法中的终结符相关的解释操作
NonterminalExpression(非终结符表达式):实现与文法中的非终结符相关的解释操作
Context(上下文):包含解释器之外的一些全局信息
Client(客户端):构建表示文法定义的语言中特定句子的抽象语法树声明一个抽象的解释操作接口
四. 代码示例
下面是一个简单的计算器示例,展示了解释器模式的应用:
import java.util.HashMap; import java.util.Map;// 抽象表达式 abstract class Expression {public abstract int interpret(Map<String, Integer> variables); }// 变量表达式(终结符表达式) class VariableExpression extends Expression {private String name;public VariableExpression(String name) {this.name = name;}@Overridepublic int interpret(Map<String, Integer> variables) {if (variables.containsKey(name)) {return variables.get(name);}throw new IllegalArgumentException("Variable not found: " + name);} }// 常量表达式(终结符表达式) class ConstantExpression extends Expression {private int value;public ConstantExpression(int value) {this.value = value;}@Overridepublic int interpret(Map<String, Integer> variables) {return value;} }// 加法表达式(非终结符表达式) class AddExpression extends Expression {private Expression left;private Expression right;public AddExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Map<String, Integer> variables) {return left.interpret(variables) + right.interpret(variables);} }// 减法表达式(非终结符表达式) class SubtractExpression extends Expression {private Expression left;private Expression right;public SubtractExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Map<String, Integer> variables) {return left.interpret(variables) - right.interpret(variables);} }// 乘法表达式(非终结符表达式) class MultiplyExpression extends Expression {private Expression left;private Expression right;public MultiplyExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Map<String, Integer> variables) {return left.interpret(variables) * right.interpret(variables);} }// 解析器 class Parser {private String[] tokens;private int position;public Parser(String expression) {this.tokens = expression.split(" ");this.position = 0;}public Expression parse() {return parseExpression();}private Expression parseExpression() {Expression left = parseTerm();while (position < tokens.length && (tokens[position].equals("+") || tokens[position].equals("-"))) {String operator = tokens[position];position++;Expression right = parseTerm();if (operator.equals("+")) {left = new AddExpression(left, right);} else if (operator.equals("-")) {left = new SubtractExpression(left, right);}}return left;}private Expression parseTerm() {Expression left = parseFactor();while (position < tokens.length && tokens[position].equals("*")) {position++;Expression right = parseFactor();left = new MultiplyExpression(left, right);}return left;}private Expression parseFactor() {if (position >= tokens.length) {throw new IllegalArgumentException("Unexpected end of expression");}String token = tokens[position++];if (token.matches("[a-zA-Z]+")) {return new VariableExpression(token);} else if (token.matches("[0-9]+")) {return new ConstantExpression(Integer.parseInt(token));} else if (token.equals("(")) {Expression expr = parseExpression();if (position >= tokens.length || !tokens[position].equals(")")) {throw new IllegalArgumentException("Missing closing parenthesis");}position++;return expr;} else {throw new IllegalArgumentException("Unexpected token: " + token);}} }// 客户端使用示例 public class InterpreterExample {public static void main(String[] args) {// 表达式: x + y * 2 - 3String expression = "x + y * 2 - 3";Parser parser = new Parser(expression);Expression expr = parser.parse();Map<String, Integer> variables = new HashMap<>();variables.put("x", 10);variables.put("y", 5);int result = expr.interpret(variables);System.out.println(expression + " = " + result); // 输出: x + y * 2 - 3 = 17// 更复杂示例: (x + y) * (z - 2)String complexExpression = "( x + y ) * ( z - 2 )";Parser complexParser = new Parser(complexExpression);Expression complexExpr = complexParser.parse();variables.put("z", 8);int complexResult = complexExpr.interpret(variables);System.out.println(complexExpression + " = " + complexResult); // 输出: ( x + y ) * ( z - 2 ) = 90} }
五. 应用场景
与到类似下面的内容,我们可以使用解释器模式:
- 规则引擎:定义业务规则并解释执行
- 表达式计算器:数学表达式的计算
- SQL 解析器:数据库查询语句的解析
- 正则表达式引擎:匹配模式的解释执行
- 模板引擎:模板语言的解析和渲染
六. 优缺点
优点:
- 易于改变和扩展文法:因为文法由类表示,所以可以使用继承来改变或扩展文法
- 易于实现文法:每条文法规则都可以表示为一个类,因此相对容易实现
- 复杂度易于控制:对于简单的文法,其实现可能过分简单;但对于复杂的文法,其复杂度会急剧增加
缺点:
- 对于复杂的文法,维护工作变得困难
- 执行效率较低:解释器模式通常使用大量的循环和递归调用,执行效率比其他设计模式低
- 类膨胀问题:如果文法包含太多表达式类型,会导致系统出现大量细粒度的类
七. 总结
解释器模式适合在以下情况下使用:
- 当有一个语言需要解释执行,并且可以将该语言的句子表示为抽象语法树时
- 当该语言的文法较为简单时
- 当效率不是关键考虑因素时
这个模式的关键在于将语言的文法规则分解成一组类,每个类代表一个语法结构,然后通过组合这些类来构建整个语法树。这使得添加新的语法元素变得更加容易,但可能会导致类的数量急剧增长。