解释器模式 (Interpreter Pattern)
给定一个语言,定义它的文法的一种表示,并定义一个解释器
模式定义
解释器模式是一种行为型设计模式,它给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。解释器模式是一种按照规定语法进行解析的方案,在现在项目中使用较少。它提供了评估语言的语法或表达式的方式,实现了文法表达式处理的接口,该接口解释一个特定的上下文。
模式结构
graph TD
A[AbstractExpression] --> B[TerminalExpression]
A --> C[NonTerminalExpression]
C --> D[Context]
实现方式
基础实现
定义抽象表达式接口,实现终结符表达式和非终结符表达式类。
// 上下文类
class Context {
private String input;
private int output;
public Context(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public int getOutput() {
return output;
}
public void setOutput(int output) {
this.output = output;
}
}
// 抽象表达式接口
interface Expression {
void interpret(Context context);
}
// 终结符表达式 - 数字
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
public NumberExpression(String number) {
this.number = Integer.parseInt(number);
}
@Override
public void interpret(Context context) {
context.setOutput(number);
}
}
// 非终结符表达式 - 加法
class AddExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public AddExpression(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public void interpret(Context context) {
// 解释左表达式
leftExpression.interpret(context);
int leftResult = context.getOutput();
// 解释右表达式
rightExpression.interpret(context);
int rightResult = context.getOutput();
// 执行加法运算
context.setOutput(leftResult + rightResult);
}
}
// 非终结符表达式 - 减法
class SubtractExpression implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public SubtractExpression(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public void interpret(Context context) {
// 解释左表达式
leftExpression.interpret(context);
int leftResult = context.getOutput();
// 解释右表达式
rightExpression.interpret(context);
int rightResult = context.getOutput();
// 执行减法运算
context.setOutput(leftResult - rightResult);
}
}
// 表达式解析器
class ExpressionParser {
private Stack stack = new Stack<>();
public Expression parse(String expression) {
String[] tokens = expression.split(" ");
for (String token : tokens) {
if (isOperator(token)) {
// 弹出右操作数和左操作数
Expression right = stack.pop();
Expression left = stack.pop();
// 创建相应的操作表达式
Expression operator = createOperator(token, left, right);
stack.push(operator);
} else {
// 数字,创建数字表达式
stack.push(new NumberExpression(token));
}
}
// 最终结果是栈中唯一的表达式
return stack.pop();
}
private boolean isOperator(String token) {
return token.equals("+") || token.equals("-");
}
private Expression createOperator(String operator, Expression left, Expression right) {
switch (operator) {
case "+":
return new AddExpression(left, right);
case "-":
return new SubtractExpression(left, right);
default:
throw new IllegalArgumentException("不支持的操作符: " + operator);
}
}
}
使用示例
public class InterpreterPatternDemo {
public static void main(String[] args) {
// 创建表达式解析器
ExpressionParser parser = new ExpressionParser();
// 解析并计算表达式: 10 + 5 - 3
String expression = "10 5 + 3 -";
Expression expr = parser.parse(expression);
Context context = new Context(expression);
expr.interpret(context);
System.out.println("表达式 '" + expression + "' 的结果是: " + context.getOutput());
// 解析并计算表达式: 20 10 - 5 +
expression = "20 10 - 5 +";
expr = parser.parse(expression);
context = new Context(expression);
expr.interpret(context);
System.out.println("表达式 '" + expression + "' 的结果是: " + context.getOutput());
}
}
经典案例
1. 正则表达式引擎
正则表达式引擎是解释器模式的一个复杂应用:
// 抽象表达式
abstract class RegexExpression {
public abstract boolean interpret(String context);
}
// 终结符表达式 - 字面量
class LiteralExpression extends RegexExpression {
private String literal;
public LiteralExpression(String literal) {
this.literal = literal;
}
@Override
public boolean interpret(String context) {
return context.contains(literal);
}
}
// 终结符表达式 - 数字
class DigitExpression extends RegexExpression {
@Override
public boolean interpret(String context) {
return context.matches(".*\\d.*");
}
}
// 非终结符表达式 - 或操作
class OrExpression extends RegexExpression {
private RegexExpression expression1;
private RegexExpression expression2;
public OrExpression(RegexExpression expression1, RegexExpression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
@Override
public boolean interpret(String context) {
return expression1.interpret(context) || expression2.interpret(context);
}
}
// 非终结符表达式 - 与操作
class AndExpression extends RegexExpression {
private RegexExpression expression1;
private RegexExpression expression2;
public AndExpression(RegexExpression expression1, RegexExpression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
@Override
public boolean interpret(String context) {
return expression1.interpret(context) && expression2.interpret(context);
}
}
// 正则表达式构建器
class RegexBuilder {
// 创建"张"或"李"的表达式
public static RegexExpression createNamePattern() {
RegexExpression zhang = new LiteralExpression("张");
RegexExpression li = new LiteralExpression("李");
return new OrExpression(zhang, li);
}
// 创建包含数字的表达式
public static RegexExpression createDigitPattern() {
return new DigitExpression();
}
// 创建姓名且包含数字的表达式
public static RegexExpression createNameWithDigitPattern() {
RegexExpression name = createNamePattern();
RegexExpression digit = createDigitPattern();
return new AndExpression(name, digit);
}
}
// 使用示例
public class RegexInterpreterDemo {
public static void main(String[] args) {
RegexExpression namePattern = RegexBuilder.createNamePattern();
RegexExpression digitPattern = RegexBuilder.createDigitPattern();
RegexExpression nameWithDigitPattern = RegexBuilder.createNameWithDigitPattern();
String[] testStrings = {
"张三",
"李四",
"王五",
"张三123",
"李四456",
"王五789",
"123456"
};
System.out.println("=== 姓名模式测试 (张或李) ===");
for (String str : testStrings) {
System.out.println("'" + str + "' 匹配姓名模式: " + namePattern.interpret(str));
}
System.out.println("\n=== 数字模式测试 ===");
for (String str : testStrings) {
System.out.println("'" + str + "' 匹配数字模式: " + digitPattern.interpret(str));
}
System.out.println("\n=== 姓名且包含数字模式测试 ===");
for (String str : testStrings) {
System.out.println("'" + str + "' 匹配姓名且包含数字模式: " + nameWithDigitPattern.interpret(str));
}
}
}
2. 布尔表达式解释器
布尔表达式的解析和计算也是解释器模式的应用:
// 上下文类
class BooleanContext {
private Map variables = new HashMap<>();
public void setVariable(String name, Boolean value) {
variables.put(name, value);
}
public Boolean getVariable(String name) {
return variables.get(name);
}
public Set getVariableNames() {
return variables.keySet();
}
}
// 抽象表达式
abstract class BooleanExpression {
public abstract boolean interpret(BooleanContext context);
}
// 终结符表达式 - 变量
class VariableExpression extends BooleanExpression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean interpret(BooleanContext context) {
Boolean value = context.getVariable(name);
return value != null ? value : false;
}
}
// 终结符表达式 - 常量
class ConstantExpression extends BooleanExpression {
private boolean value;
public ConstantExpression(boolean value) {
this.value = value;
}
@Override
public boolean interpret(BooleanContext context) {
return value;
}
}
// 非终结符表达式 - 与操作
class AndExpression extends BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public AndExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(BooleanContext context) {
return left.interpret(context) && right.interpret(context);
}
}
// 非终结符表达式 - 或操作
class OrExpression extends BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public OrExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(BooleanContext context) {
return left.interpret(context) || right.interpret(context);
}
}
// 非终结符表达式 - 非操作
class NotExpression extends BooleanExpression {
private BooleanExpression expression;
public NotExpression(BooleanExpression expression) {
this.expression = expression;
}
@Override
public boolean interpret(BooleanContext context) {
return !expression.interpret(context);
}
}
// 布尔表达式解析器
class BooleanExpressionParser {
public BooleanExpression parse(String expression) {
// 简单的解析器实现,仅支持基本的布尔表达式
// 实际应用中需要更复杂的词法和语法分析
// 移除空格
expression = expression.replaceAll("\\s+", "");
// 处理非操作
if (expression.startsWith("!")) {
BooleanExpression operand = parse(expression.substring(1));
return new NotExpression(operand);
}
// 处理括号
if (expression.startsWith("(") && expression.endsWith(")")) {
// 简化处理,实际需要考虑嵌套括号
return parse(expression.substring(1, expression.length() - 1));
}
// 处理与操作
int andIndex = expression.indexOf("&&");
if (andIndex != -1) {
BooleanExpression left = parse(expression.substring(0, andIndex));
BooleanExpression right = parse(expression.substring(andIndex + 2));
return new AndExpression(left, right);
}
// 处理或操作
int orIndex = expression.indexOf("||");
if (orIndex != -1) {
BooleanExpression left = parse(expression.substring(0, orIndex));
BooleanExpression right = parse(expression.substring(orIndex + 2));
return new OrExpression(left, right);
}
// 处理常量
if (expression.equals("true")) {
return new ConstantExpression(true);
}
if (expression.equals("false")) {
return new ConstantExpression(false);
}
// 默认为变量
return new VariableExpression(expression);
}
}
// 使用示例
public class BooleanInterpreterDemo {
public static void main(String[] args) {
// 创建表达式解析器
BooleanExpressionParser parser = new BooleanExpressionParser();
// 解析布尔表达式: a && (b || c)
String expressionStr = "a&&(b||c)";
BooleanExpression expression = parser.parse(expressionStr);
// 创建上下文并设置变量值
BooleanContext context = new BooleanContext();
context.setVariable("a", true);
context.setVariable("b", false);
context.setVariable("c", true);
// 解释表达式
boolean result = expression.interpret(context);
System.out.println("表达式 '" + expressionStr + "' 的结果: " + result);
// 测试不同的变量值
context.setVariable("a", false);
result = expression.interpret(context);
System.out.println("当 a=false, b=false, c=true 时,表达式 '" + expressionStr + "' 的结果: " + result);
// 解析更复杂的表达式: (a || b) && !c
expressionStr = "(a||b)&&!c";
expression = parser.parse(expressionStr);
context.setVariable("a", true);
context.setVariable("b", false);
context.setVariable("c", false);
result = expression.interpret(context);
System.out.println("表达式 '" + expressionStr + "' 的结果: " + result);
}
}
应用场景
- 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树
- 一些重复出现的问题可以用一种简单的语言来进行表达
- 正则表达式引擎
- 编程语言的编译器
- 规则引擎
- 数学表达式计算器
- SQL解析器
- 配置文件解析
优缺点
优点
- 可扩展性好:在语法树中增加新的节点类非常方便,符合开闭原则
- 容易实现:对于简单的文法,实现起来相对容易
- 灵活性强:可以方便地改变和扩展文法
- 易于维护:每条语法规则都可以单独维护
缺点
- 执行效率较低:大量使用循环和递归调用,性能一般
- 复杂度高:对于复杂的文法,类的设计比较困难
- 适用场景有限:只在特定的场景下使用,适用范围不广
- 增加系统复杂性:引入大量类,增加系统复杂性