解释器模式详解
目录
模式简介
定义
解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一个语言的文法,并且建立一个解释器来解释该语言中的句子。解释器模式通常用于需要解释和执行用某种语言编写的语句或表达式的场景。
核心思想
- 文法定义:定义语言的文法规则
- 语法树构建:将句子解析为抽象语法树
- 解释执行:通过遍历语法树来解释执行
- 扩展性:易于扩展新的文法规则
模式结构
- AbstractExpression(抽象表达式):声明一个抽象的解释操作
- TerminalExpression(终结符表达式):实现与文法中的终结符相关的解释操作
- NonterminalExpression(非终结符表达式):实现与文法中的非终结符相关的解释操作
- Context(上下文):包含解释器之外的一些全局信息
- Client(客户端):构建抽象语法树并调用解释操作
核心流程
基本流程图
客户端输入表达式 词法分析器 语法分析器 构建抽象语法树 解释器遍历语法树 执行解释操作 返回解释结果
语法树构建流程
输入表达式字符串 词法分析 生成Token序列 语法分析 构建AST节点 递归构建子树 完成抽象语法树
解释执行流程
开始解释 访问根节点 判断节点类型 终结符节点 非终结符节点 直接返回值 递归解释子节点 组合子节点结果 返回组合结果 解释完成
详细流程步骤
1. 词法分析流程
输入字符串 字符扫描 识别Token类型 数字Token 操作符Token 括号Token 生成NumberToken 生成OperatorToken 生成BracketToken Token序列
2. 语法分析流程
Token序列 递归下降分析 解析表达式 解析项 解析因子 处理括号 构建语法树节点 返回AST根节点
代码示例流程
java
// 1. 词法分析
Lexer lexer = new Lexer("2 + 3 * 4");
List<Token> tokens = lexer.tokenize();
// 2. 语法分析
Parser parser = new Parser(tokens);
Expression ast = parser.parse();
// 3. 解释执行
Interpreter interpreter = new Interpreter();
int result = interpreter.interpret(ast);
重难点分析
重点分析
1. 抽象语法树构建
java
// 抽象表达式接口
public interface Expression {
int interpret(Context context);
}
// 终结符表达式(数字)
public class NumberExpression implements Expression {
private int value;
public NumberExpression(int value) {
this.value = value;
}
@Override
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式(加法)
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(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 非终结符表达式(乘法)
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(Context context) {
return left.interpret(context) * right.interpret(context);
}
}
2. 递归下降语法分析器
java
public class Parser {
private List<Token> tokens;
private int current = 0;
public Parser(List<Token> tokens) {
this.tokens = tokens;
}
// 解析表达式(处理 + 和 -)
public Expression parseExpression() {
Expression left = parseTerm();
while (match(TokenType.PLUS) || match(TokenType.MINUS)) {
Token operator = previous();
Expression right = parseTerm();
if (operator.getType() == TokenType.PLUS) {
left = new AddExpression(left, right);
} else {
left = new SubtractExpression(left, right);
}
}
return left;
}
// 解析项(处理 * 和 /)
private Expression parseTerm() {
Expression left = parseFactor();
while (match(TokenType.MULTIPLY) || match(TokenType.DIVIDE)) {
Token operator = previous();
Expression right = parseFactor();
if (operator.getType() == TokenType.MULTIPLY) {
left = new MultiplyExpression(left, right);
} else {
left = new DivideExpression(left, right);
}
}
return left;
}
// 解析因子(处理数字和括号)
private Expression parseFactor() {
if (match(TokenType.NUMBER)) {
return new NumberExpression(Integer.parseInt(previous().getValue()));
}
if (match(TokenType.LEFT_PAREN)) {
Expression expr = parseExpression();
consume(TokenType.RIGHT_PAREN, "期望 ')'");
return expr;
}
throw new RuntimeException("期望表达式");
}
}
3. 上下文管理
java
public class Context {
private Map<String, Integer> variables = new HashMap<>();
public void setVariable(String name, int value) {
variables.put(name, value);
}
public int getVariable(String name) {
return variables.getOrDefault(name, 0);
}
// 支持函数调用
private Map<String, Function> functions = new HashMap<>();
public void defineFunction(String name, Function function) {
functions.put(name, function);
}
public Function getFunction(String name) {
return functions.get(name);
}
}
// 变量表达式
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);
}
}
难点分析
1. 运算符优先级处理
java
public class PrecedenceParser {
private List<Token> tokens;
private int current = 0;
// 运算符优先级表
private static final Map<TokenType, Integer> PRECEDENCE = Map.of(
TokenType.PLUS, 1,
TokenType.MINUS, 1,
TokenType.MULTIPLY, 2,
TokenType.DIVIDE, 2,
TokenType.POWER, 3
);
public Expression parseExpression() {
return parsePrecedence(0);
}
private Expression parsePrecedence(int precedence) {
Expression left = parseUnary();
while (current < tokens.size() &&
PRECEDENCE.getOrDefault(peek().getType(), 0) >= precedence) {
Token operator = advance();
int rightPrecedence = PRECEDENCE.get(operator.getType()) + 1;
Expression right = parsePrecedence(rightPrecedence);
left = createBinaryExpression(operator, left, right);
}
return left;
}
private Expression createBinaryExpression(Token operator, Expression left, Expression right) {
switch (operator.getType()) {
case PLUS: return new AddExpression(left, right);
case MINUS: return new SubtractExpression(left, right);
case MULTIPLY: return new MultiplyExpression(left, right);
case DIVIDE: return new DivideExpression(left, right);
case POWER: return new PowerExpression(left, right);
default: throw new RuntimeException("未知操作符");
}
}
}
2. 错误处理和恢复
java
public class ErrorRecoveryParser {
private List<Token> tokens;
private int current = 0;
private List<ParseError> errors = new ArrayList<>();
public Expression parse() {
try {
return parseExpression();
} catch (ParseError error) {
errors.add(error);
return recoverFromError();
}
}
private Expression recoverFromError() {
// 跳过错误token
while (current < tokens.size() && !isAtEnd()) {
if (peek().getType() == TokenType.SEMICOLON) {
advance();
break;
}
advance();
}
// 返回默认表达式
return new NumberExpression(0);
}
private void synchronize() {
advance();
while (!isAtEnd()) {
if (previous().getType() == TokenType.SEMICOLON) return;
switch (peek().getType()) {
case CLASS:
case FUNCTION:
case VAR:
case FOR:
case IF:
case WHILE:
case PRINT:
case RETURN:
return;
}
advance();
}
}
}
3. 内存管理和优化
java
public class OptimizedInterpreter {
// 使用对象池避免频繁创建对象
private final ObjectPool<NumberExpression> numberPool = new ObjectPool<>();
private final ObjectPool<AddExpression> addPool = new ObjectPool<>();
public Expression createNumberExpression(int value) {
NumberExpression expr = numberPool.acquire();
if (expr == null) {
expr = new NumberExpression(value);
} else {
expr.setValue(value);
}
return expr;
}
public void releaseExpression(Expression expr) {
if (expr instanceof NumberExpression) {
numberPool.release((NumberExpression) expr);
} else if (expr instanceof AddExpression) {
addPool.release((AddExpression) expr);
}
}
// 使用缓存避免重复计算
private final Map<String, Integer> expressionCache = new HashMap<>();
public int interpretWithCache(Expression expr, Context context) {
String key = expr.toString() + context.toString();
return expressionCache.computeIfAbsent(key, k -> expr.interpret(context));
}
}
Spring中的源码分析
1. SpEL表达式解释器
核心类:SpelExpressionParser
java
public class SpelExpressionParser {
public SpelExpression parseExpression(String expressionString) {
// 词法分析
SpelTokenizer tokenizer = new SpelTokenizer(expressionString);
List<Token> tokens = tokenizer.tokenize();
// 语法分析
SpelParser parser = new SpelParser(tokens);
SpelNode ast = parser.parseExpression();
// 创建表达式对象
return new SpelExpression(ast, expressionString);
}
}
// SpEL表达式节点
public abstract class SpelNode {
protected SpelNode[] children;
public abstract TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException;
// 访问者模式遍历节点
public void accept(SpelNodeVisitor visitor) {
visitor.visit(this);
if (children != null) {
for (SpelNode child : children) {
child.accept(visitor);
}
}
}
}
// 字面量节点
public class Literal extends SpelNode {
private Object value;
@Override
public TypedValue getValueInternal(ExpressionState expressionState) {
return new TypedValue(value);
}
}
// 方法调用节点
public class MethodReference extends SpelNode {
private String methodName;
@Override
public TypedValue getValueInternal(ExpressionState expressionState) throws EvaluationException {
// 获取目标对象
TypedValue target = children[0].getValueInternal(expressionState);
Object targetObject = target.getValue();
// 获取方法参数
Object[] args = new Object[children.length - 1];
for (int i = 1; i < children.length; i++) {
args[i - 1] = children[i].getValueInternal(expressionState).getValue();
}
// 调用方法
Method method = findMethod(targetObject.getClass(), methodName, args);
Object result = method.invoke(targetObject, args);
return new TypedValue(result);
}
}
2. 配置属性表达式解释器
核心类:PropertyResolver
java
public interface PropertyResolver {
String resolvePlaceholders(String text);
String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;
}
// 属性解析器实现
public class PropertySourcesPropertyResolver implements PropertyResolver {
private final PropertySources propertySources;
private final PlaceholderResolver placeholderResolver;
@Override
public String resolvePlaceholders(String text) {
if (text == null) {
return null;
}
// 使用解释器模式解析占位符
return placeholderResolver.resolvePlaceholders(text);
}
}
// 占位符解析器
public class PlaceholderResolver {
public String resolvePlaceholders(String text) {
// 词法分析:识别占位符
List<PlaceholderToken> tokens = tokenize(text);
// 语法分析:构建AST
PlaceholderAST ast = parse(tokens);
// 解释执行:解析占位符
return interpret(ast);
}
private List<PlaceholderToken> tokenize(String text) {
List<PlaceholderToken> tokens = new ArrayList<>();
Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
tokens.add(new PlaceholderToken(matcher.group(1)));
}
return tokens;
}
}
3. 条件表达式解释器
核心类:ConditionEvaluator
java
public class ConditionEvaluator {
public boolean evaluate(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取条件注解
Conditional conditional = metadata.getAnnotations().get(Conditional.class);
if (conditional == null) {
return true;
}
// 解析条件表达式
String[] conditions = conditional.value();
for (String condition : conditions) {
if (!evaluateCondition(condition, context)) {
return false;
}
}
return true;
}
private boolean evaluateCondition(String condition, ConditionContext context) {
// 词法分析
List<ConditionToken> tokens = tokenizeCondition(condition);
// 语法分析
ConditionAST ast = parseCondition(tokens);
// 解释执行
return interpretCondition(ast, context);
}
private boolean interpretCondition(ConditionAST ast, ConditionContext context) {
if (ast instanceof AndCondition) {
return interpretCondition(ast.getLeft(), context) &&
interpretCondition(ast.getRight(), context);
} else if (ast instanceof OrCondition) {
return interpretCondition(ast.getLeft(), context) ||
interpretCondition(ast.getRight(), context);
} else if (ast instanceof PropertyCondition) {
return evaluatePropertyCondition((PropertyCondition) ast, context);
}
return false;
}
}
4. 路由表达式解释器
核心类:PathMatcher
java
public interface PathMatcher {
boolean match(String pattern, String path);
String extractPathWithinPattern(String pattern, String path);
}
// Ant路径匹配器
public class AntPathMatcher implements PathMatcher {
@Override
public boolean match(String pattern, String path) {
// 解析路径模式
PathPattern pathPattern = parsePattern(pattern);
// 匹配路径
return pathPattern.matches(path);
}
private PathPattern parsePattern(String pattern) {
// 词法分析:识别路径组件
List<PathToken> tokens = tokenizePath(pattern);
// 语法分析:构建路径模式AST
PathPatternAST ast = parsePathPattern(tokens);
// 创建路径模式对象
return new PathPattern(ast);
}
private List<PathToken> tokenizePath(String pattern) {
List<PathToken> tokens = new ArrayList<>();
String[] components = pattern.split("/");
for (String component : components) {
if (component.equals("**")) {
tokens.add(new WildcardToken());
} else if (component.contains("*")) {
tokens.add(new PatternToken(component));
} else {
tokens.add(new LiteralToken(component));
}
}
return tokens;
}
}
具体使用场景
1. 数学表达式计算器
java
// 数学表达式解释器
public class MathExpressionInterpreter {
public static void main(String[] args) {
String expression = "2 + 3 * 4 - 1";
// 词法分析
MathLexer lexer = new MathLexer(expression);
List<Token> tokens = lexer.tokenize();
// 语法分析
MathParser parser = new MathParser(tokens);
Expression ast = parser.parse();
// 解释执行
MathInterpreter interpreter = new MathInterpreter();
int result = interpreter.interpret(ast);
System.out.println(expression + " = " + result);
}
}
// 数学表达式词法分析器
public class MathLexer {
private String input;
private int position = 0;
public MathLexer(String input) {
this.input = input;
}
public List<Token> tokenize() {
List<Token> tokens = new ArrayList<>();
while (position < input.length()) {
char current = input.charAt(position);
if (Character.isDigit(current)) {
tokens.add(readNumber());
} else if (current == '+') {
tokens.add(new Token(TokenType.PLUS, "+"));
position++;
} else if (current == '-') {
tokens.add(new Token(TokenType.MINUS, "-"));
position++;
} else if (current == '*') {
tokens.add(new Token(TokenType.MULTIPLY, "*"));
position++;
} else if (current == '/') {
tokens.add(new Token(TokenType.DIVIDE, "/"));
position++;
} else if (current == '(') {
tokens.add(new Token(TokenType.LEFT_PAREN, "("));
position++;
} else if (current == ')') {
tokens.add(new Token(TokenType.RIGHT_PAREN, ")"));
position++;
} else if (Character.isWhitespace(current)) {
position++;
} else {
throw new RuntimeException("未知字符: " + current);
}
}
return tokens;
}
private Token readNumber() {
StringBuilder number = new StringBuilder();
while (position < input.length() && Character.isDigit(input.charAt(position))) {
number.append(input.charAt(position));
position++;
}
return new Token(TokenType.NUMBER, number.toString());
}
}
2. SQL查询解释器
java
// SQL查询解释器
public class SQLInterpreter {
public QueryResult execute(String sql) {
// 词法分析
SQLLexer lexer = new SQLLexer(sql);
List<SQLToken> tokens = lexer.tokenize();
// 语法分析
SQLParser parser = new SQLParser(tokens);
SQLAST ast = parser.parse();
// 解释执行
return interpret(ast);
}
private QueryResult interpret(SQLAST ast) {
if (ast instanceof SelectStatement) {
return interpretSelect((SelectStatement) ast);
} else if (ast instanceof InsertStatement) {
return interpretInsert((InsertStatement) ast);
} else if (ast instanceof UpdateStatement) {
return interpretUpdate((UpdateStatement) ast);
} else if (ast instanceof DeleteStatement) {
return interpretDelete((DeleteStatement) ast);
}
throw new RuntimeException("不支持的SQL语句类型");
}
private QueryResult interpretSelect(SelectStatement select) {
// 解析SELECT子句
List<Column> columns = interpretColumns(select.getColumns());
// 解析FROM子句
Table table = interpretTable(select.getTable());
// 解析WHERE子句
Condition whereCondition = interpretCondition(select.getWhereClause());
// 执行查询
return executeQuery(table, columns, whereCondition);
}
}
// SQL AST节点
public abstract class SQLAST {
public abstract QueryResult interpret(SQLInterpreter interpreter);
}
// SELECT语句节点
public class SelectStatement extends SQLAST {
private List<Column> columns;
private Table table;
private Condition whereClause;
@Override
public QueryResult interpret(SQLInterpreter interpreter) {
return interpreter.interpretSelect(this);
}
}
// WHERE条件节点
public class WhereCondition extends SQLAST {
private Expression left;
private String operator;
private Expression right;
@Override
public QueryResult interpret(SQLInterpreter interpreter) {
return interpreter.interpretWhereCondition(this);
}
}
3. 规则引擎
java
// 规则引擎解释器
public class RuleEngine {
private Map<String, Rule> rules = new HashMap<>();
public void addRule(String name, String ruleExpression) {
// 解析规则表达式
Rule rule = parseRule(ruleExpression);
rules.put(name, rule);
}
public boolean evaluateRule(String ruleName, Map<String, Object> facts) {
Rule rule = rules.get(ruleName);
if (rule == null) {
throw new RuntimeException("规则不存在: " + ruleName);
}
// 创建规则上下文
RuleContext context = new RuleContext(facts);
// 解释执行规则
return rule.interpret(context);
}
private Rule parseRule(String ruleExpression) {
// 词法分析
RuleLexer lexer = new RuleLexer(ruleExpression);
List<RuleToken> tokens = lexer.tokenize();
// 语法分析
RuleParser parser = new RuleParser(tokens);
return parser.parseRule();
}
}
// 规则接口
public interface Rule {
boolean interpret(RuleContext context);
}
// 复合规则(AND)
public class AndRule implements Rule {
private Rule left;
private Rule right;
public AndRule(Rule left, Rule right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(RuleContext context) {
return left.interpret(context) && right.interpret(context);
}
}
// 条件规则
public class ConditionRule implements Rule {
private String factName;
private String operator;
private Object expectedValue;
@Override
public boolean interpret(RuleContext context) {
Object actualValue = context.getFact(factName);
switch (operator) {
case "==": return Objects.equals(actualValue, expectedValue);
case "!=": return !Objects.equals(actualValue, expectedValue);
case ">": return compare(actualValue, expectedValue) > 0;
case "<": return compare(actualValue, expectedValue) < 0;
case ">=": return compare(actualValue, expectedValue) >= 0;
case "<=": return compare(actualValue, expectedValue) <= 0;
default: throw new RuntimeException("未知操作符: " + operator);
}
}
}
4. 模板引擎
java
// 模板引擎解释器
public class TemplateEngine {
public String render(String template, Map<String, Object> variables) {
// 词法分析:识别模板标签
List<TemplateToken> tokens = tokenizeTemplate(template);
// 语法分析:构建模板AST
TemplateAST ast = parseTemplate(tokens);
// 解释执行:渲染模板
return interpretTemplate(ast, variables);
}
private List<TemplateToken> tokenizeTemplate(String template) {
List<TemplateToken> tokens = new ArrayList<>();
Pattern pattern = Pattern.compile("\\{\\{([^}]+)\\}\\}|\\{%([^%]+)%\\}");
Matcher matcher = pattern.matcher(template);
int lastEnd = 0;
while (matcher.find()) {
// 添加文本内容
if (matcher.start() > lastEnd) {
tokens.add(new TextToken(template.substring(lastEnd, matcher.start())));
}
// 添加变量标签
if (matcher.group(1) != null) {
tokens.add(new VariableToken(matcher.group(1).trim()));
}
// 添加控制标签
else if (matcher.group(2) != null) {
tokens.add(new ControlToken(matcher.group(2).trim()));
}
lastEnd = matcher.end();
}
// 添加剩余文本
if (lastEnd < template.length()) {
tokens.add(new TextToken(template.substring(lastEnd)));
}
return tokens;
}
private String interpretTemplate(TemplateAST ast, Map<String, Object> variables) {
StringBuilder result = new StringBuilder();
interpretNode(ast, variables, result);
return result.toString();
}
private void interpretNode(TemplateAST node, Map<String, Object> variables, StringBuilder result) {
if (node instanceof TextNode) {
result.append(((TextNode) node).getText());
} else if (node instanceof VariableNode) {
String varName = ((VariableNode) node).getVariableName();
Object value = variables.get(varName);
result.append(value != null ? value.toString() : "");
} else if (node instanceof IfNode) {
interpretIfNode((IfNode) node, variables, result);
} else if (node instanceof ForNode) {
interpretForNode((ForNode) node, variables, result);
}
}
}
5. 配置表达式解释器
java
// 配置表达式解释器
public class ConfigExpressionInterpreter {
public Object evaluate(String expression, Map<String, Object> config) {
// 词法分析
ConfigLexer lexer = new ConfigLexer(expression);
List<ConfigToken> tokens = lexer.tokenize();
// 语法分析
ConfigParser parser = new ConfigParser(tokens);
ConfigAST ast = parser.parse();
// 解释执行
return interpret(ast, config);
}
private Object interpret(ConfigAST ast, Map<String, Object> config) {
if (ast instanceof ConfigValueNode) {
return interpretValue((ConfigValueNode) ast, config);
} else if (ast instanceof ConfigExpressionNode) {
return interpretExpression((ConfigExpressionNode) ast, config);
} else if (ast instanceof ConfigFunctionNode) {
return interpretFunction((ConfigFunctionNode) ast, config);
}
throw new RuntimeException("不支持的配置表达式类型");
}
private Object interpretValue(ConfigValueNode node, Map<String, Object> config) {
String key = node.getKey();
Object value = config.get(key);
if (value == null) {
throw new RuntimeException("配置项不存在: " + key);
}
return value;
}
private Object interpretExpression(ConfigExpressionNode node, Map<String, Object> config) {
Object left = interpret(node.getLeft(), config);
Object right = interpret(node.getRight(), config);
String operator = node.getOperator();
switch (operator) {
case "+": return add(left, right);
case "-": return subtract(left, right);
case "*": return multiply(left, right);
case "/": return divide(left, right);
case "==": return Objects.equals(left, right);
case "!=": return !Objects.equals(left, right);
default: throw new RuntimeException("未知操作符: " + operator);
}
}
}
面试高频点
1. 基本概念类
Q: 什么是解释器模式?
A: 解释器模式是一种行为型设计模式,它定义了一个语言的文法,并且建立一个解释器来解释该语言中的句子。它通常用于需要解释和执行用某种语言编写的语句或表达式的场景。
Q: 解释器模式的核心组件有哪些?
A:
- AbstractExpression(抽象表达式):声明一个抽象的解释操作
- TerminalExpression(终结符表达式):实现与文法中的终结符相关的解释操作
- NonterminalExpression(非终结符表达式):实现与文法中的非终结符相关的解释操作
- Context(上下文):包含解释器之外的一些全局信息
- Client(客户端):构建抽象语法树并调用解释操作
2. 设计原理类
Q: 解释器模式与编译器模式的区别?
A:
- 解释器模式:运行时解释执行,每次执行都需要重新解释
- 编译器模式:编译时生成机器码,执行时直接运行机器码
- 解释器模式:灵活性高,但性能较低
- 编译器模式:性能高,但灵活性较低
Q: 解释器模式如何实现运算符优先级?
A:
java
public class PrecedenceParser {
private static final Map<TokenType, Integer> PRECEDENCE = Map.of(
TokenType.PLUS, 1,
TokenType.MINUS, 1,
TokenType.MULTIPLY, 2,
TokenType.DIVIDE, 2,
TokenType.POWER, 3
);
private Expression parsePrecedence(int precedence) {
Expression left = parseUnary();
while (current < tokens.size() &&
PRECEDENCE.getOrDefault(peek().getType(), 0) >= precedence) {
Token operator = advance();
int rightPrecedence = PRECEDENCE.get(operator.getType()) + 1;
Expression right = parsePrecedence(rightPrecedence);
left = createBinaryExpression(operator, left, right);
}
return left;
}
}
3. 实现细节类
Q: 如何实现递归下降语法分析器?
A:
java
public class RecursiveDescentParser {
private List<Token> tokens;
private int current = 0;
// 解析表达式
public Expression parseExpression() {
return parseEquality();
}
// 解析相等性
private Expression parseEquality() {
Expression left = parseComparison();
while (match(TokenType.BANG_EQUAL, TokenType.EQUAL_EQUAL)) {
Token operator = previous();
Expression right = parseComparison();
left = new BinaryExpression(left, operator, right);
}
return left;
}
// 解析比较
private Expression parseComparison() {
Expression left = parseTerm();
while (match(TokenType.GREATER, TokenType.GREATER_EQUAL,
TokenType.LESS, TokenType.LESS_EQUAL)) {
Token operator = previous();
Expression right = parseTerm();
left = new BinaryExpression(left, operator, right);
}
return left;
}
}
Q: 如何实现错误处理和恢复?
A:
java
public class ErrorRecoveryParser {
private List<ParseError> errors = new ArrayList<>();
public Expression parse() {
try {
return parseExpression();
} catch (ParseError error) {
errors.add(error);
synchronize();
return new ErrorExpression();
}
}
private void synchronize() {
advance();
while (!isAtEnd()) {
if (previous().getType() == TokenType.SEMICOLON) return;
switch (peek().getType()) {
case CLASS:
case FUNCTION:
case VAR:
case FOR:
case IF:
case WHILE:
case PRINT:
case RETURN:
return;
}
advance();
}
}
}
4. 性能优化类
Q: 解释器模式可能遇到哪些性能问题?
A:
- 重复解析:每次执行都需要重新解析
- 内存占用:AST节点占用大量内存
- 方法调用开销:递归调用导致性能损失
解决方案:
java
// 使用缓存避免重复解析
public class CachedInterpreter {
private Map<String, Expression> expressionCache = new HashMap<>();
public Object interpret(String expression, Context context) {
Expression ast = expressionCache.computeIfAbsent(expression,
expr -> parseExpression(expr));
return ast.interpret(context);
}
}
// 使用对象池减少对象创建
public class ObjectPoolInterpreter {
private final ObjectPool<NumberExpression> numberPool = new ObjectPool<>();
public Expression createNumberExpression(int value) {
NumberExpression expr = numberPool.acquire();
if (expr == null) {
expr = new NumberExpression(value);
} else {
expr.setValue(value);
}
return expr;
}
}
5. 实际应用类
Q: 在Spring框架中,哪些地方使用了解释器模式?
A:
- SpEL表达式:SpelExpressionParser解析SpEL表达式
- 配置属性:PropertyResolver解析占位符表达式
- 条件表达式:ConditionEvaluator解析条件注解
- 路径匹配:PathMatcher解析路径模式
Q: 解释器模式在规则引擎中的应用?
A:
java
// 规则引擎解释器
public class RuleEngine {
public boolean evaluateRule(String ruleExpression, Map<String, Object> facts) {
// 解析规则表达式
Rule rule = parseRule(ruleExpression);
// 创建规则上下文
RuleContext context = new RuleContext(facts);
// 解释执行规则
return rule.interpret(context);
}
private Rule parseRule(String ruleExpression) {
// 词法分析
RuleLexer lexer = new RuleLexer(ruleExpression);
List<RuleToken> tokens = lexer.tokenize();
// 语法分析
RuleParser parser = new RuleParser(tokens);
return parser.parseRule();
}
}
6. 设计权衡类
Q: 解释器模式的优缺点?
A:
优点:
- 易于实现简单的文法
- 易于扩展和修改文法
- 符合开闭原则
- 可以动态解释执行
缺点:
- 复杂文法难以维护
- 性能较低
- 难以调试
- 内存占用较大
Q: 什么时候不应该使用解释器模式?
A:
- 文法复杂:复杂文法难以用解释器模式实现
- 性能要求高:解释器模式性能较低
- 文法稳定:稳定的文法可以用编译器模式
- 简单表达式:简单表达式不需要复杂的解释器
使用总结
适用场景总结
1. 必须使用解释器模式的场景
- 表达式计算:数学表达式、逻辑表达式
- 查询语言:SQL、XPath、JSONPath
- 规则引擎:业务规则、决策规则
- 模板引擎:文本模板、HTML模板
- 配置解析:配置文件、环境变量
2. 可以考虑使用的场景
- 脚本语言:简单的脚本语言解释器
- 数据转换:数据格式转换规则
- 验证规则:数据验证规则
- 路由规则:URL路由规则
最佳实践建议
1. 文法设计原则
java
// 建议:使用递归下降解析器
public class RecursiveDescentParser {
// 每个非终结符对应一个方法
private Expression parseExpression() {
return parseEquality();
}
private Expression parseEquality() {
Expression left = parseComparison();
while (match(TokenType.BANG_EQUAL, TokenType.EQUAL_EQUAL)) {
Token operator = previous();
Expression right = parseComparison();
left = new BinaryExpression(left, operator, right);
}
return left;
}
}
2. 错误处理建议
java
// 建议:实现完善的错误处理
public class RobustParser {
private List<ParseError> errors = new ArrayList<>();
public Expression parse() {
try {
return parseExpression();
} catch (ParseError error) {
errors.add(error);
return recoverFromError();
}
}
private Expression recoverFromError() {
synchronize();
return new ErrorExpression();
}
private void synchronize() {
// 同步到下一个语句
while (!isAtEnd()) {
if (previous().getType() == TokenType.SEMICOLON) return;
switch (peek().getType()) {
case CLASS:
case FUNCTION:
case VAR:
return;
}
advance();
}
}
}
3. 性能优化建议
java
// 建议:使用缓存和对象池
public class OptimizedInterpreter {
// 表达式缓存
private Map<String, Expression> expressionCache = new HashMap<>();
// 对象池
private final ObjectPool<NumberExpression> numberPool = new ObjectPool<>();
public Object interpret(String expression, Context context) {
// 使用缓存
Expression ast = expressionCache.computeIfAbsent(expression,
expr -> parseExpression(expr));
// 使用对象池
return interpretWithPool(ast, context);
}
}
与其他模式的结合
1. 与访问者模式结合
java
// 解释器模式与访问者模式结合
public class InterpreterVisitor implements ExpressionVisitor {
private Context context;
public InterpreterVisitor(Context context) {
this.context = context;
}
@Override
public Object visit(NumberExpression expr) {
return expr.getValue();
}
@Override
public Object visit(AddExpression expr) {
Object left = expr.getLeft().accept(this);
Object right = expr.getRight().accept(this);
return add(left, right);
}
}
2. 与策略模式结合
java
// 解释器模式与策略模式结合
public class StrategyInterpreter {
private Map<String, InterpretationStrategy> strategies = new HashMap<>();
public Object interpret(String expression, Context context) {
String strategyKey = determineStrategy(expression);
InterpretationStrategy strategy = strategies.get(strategyKey);
return strategy.interpret(expression, context);
}
private String determineStrategy(String expression) {
if (expression.contains("+") || expression.contains("-")) {
return "arithmetic";
} else if (expression.contains("&&") || expression.contains("||")) {
return "logical";
} else {
return "literal";
}
}
}
总结
解释器模式是一个强大的设计模式,特别适用于需要解释和执行用某种语言编写的语句或表达式的场景。通过定义语言的文法和建立解释器,它实现了灵活的语言处理能力。
关键要点:
- 文法定义:明确定义语言的文法规则
- 语法树构建:将句子解析为抽象语法树
- 解释执行:通过遍历语法树来解释执行
- 错误处理:实现完善的错误处理和恢复机制
- 性能优化:使用缓存和对象池提高性能
适用场景:
- 表达式计算
- 查询语言
- 规则引擎
- 模板引擎
- 配置解析
注意事项:
- 复杂文法难以维护
- 性能相对较低
- 需要完善的错误处理
- 内存占用较大