解释器模式
大约 12 分钟
解释器模式
什么是解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,它给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
解释器模式的核心思想是:
- 定义语言的文法表示
- 构建解释器来解释语言中的句子
- 将每一个语法规则表示为一个类
为什么需要解释器模式
在实际开发中,我们经常会遇到需要处理特定领域语言(DSL)的情况,比如:
- 正则表达式
- SQL查询语句
- 数学表达式
- 配置文件语法
- 脚本语言
解释器模式通过定义语法规则的类表示,使得我们可以用面向对象的方式来处理这些语言,从而提供了一种灵活的解决方案。
解释器模式的结构
解释器模式包含以下几个角色:
- 抽象表达式(AbstractExpression):声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享
- 终结符表达式(TerminalExpression):实现文法中的终结符相关的解释操作
- 非终结符表达式(NonterminalExpression):为文法中的非终结符实现解释操作
- 环境(Context):包含解释器之外的一些全局信息
- 客户端(Client):构建表示文法定义的语言中一个特定句子的抽象语法树,然后调用解释操作
解释器模式的实现
基本实现
// 抽象表达式
interface Expression {
boolean interpret(String context);
}
// 终结符表达式 - 终端
class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data = data;
}
@Override
public boolean interpret(String context) {
return context.contains(data);
}
}
// 非终结符表达式 - 或操作
class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
// 非终结符表达式 - 与操作
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
@Override
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
// 使用示例
public class InterpreterDemo {
// 创建规则
public static Expression getMaleExpression() {
Expression robert = new TerminalExpression("Robert");
Expression john = new TerminalExpression("John");
return new OrExpression(robert, john);
}
public static Expression getMarriedWomanExpression() {
Expression julie = new TerminalExpression("Julie");
Expression married = new TerminalExpression("Married");
return new AndExpression(julie, married);
}
public static void main(String[] args) {
Expression isMale = getMaleExpression();
Expression isMarriedWoman = getMarriedWomanExpression();
System.out.println("John is male? " + isMale.interpret("John"));
System.out.println("Julie is a married woman? " + isMarriedWoman.interpret("Married Julie"));
System.out.println("Robert is a married woman? " + isMarriedWoman.interpret("Robert"));
}
}
实际应用示例
// 数学表达式解释器示例
// 抽象表达式
interface Expression {
int interpret();
}
// 环境类
class Context {
private Map<String, Integer> variables = new HashMap<>();
public void setVariable(String name, Integer value) {
variables.put(name, value);
}
public Integer getVariable(String name) {
return variables.get(name);
}
public boolean hasVariable(String name) {
return variables.containsKey(name);
}
}
// 数字表达式(终结符)
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
// 变量表达式(终结符)
class VariableExpression implements Expression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public int interpret() {
throw new UnsupportedOperationException("需要在上下文中解释变量");
}
public int interpret(Context context) {
if (!context.hasVariable(name)) {
throw new IllegalArgumentException("未定义的变量: " + name);
}
return context.getVariable(name);
}
}
// 加法表达式(非终结符)
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() {
return left.interpret() + right.interpret();
}
}
// 减法表达式(非终结符)
class SubtractExpression implements Expression {
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() - right.interpret();
}
}
// 乘法表达式(非终结符)
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() {
return left.interpret() * right.interpret();
}
}
// 除法表达式(非终结符)
class DivideExpression implements Expression {
private Expression left;
private Expression right;
public DivideExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
int divisor = right.interpret();
if (divisor == 0) {
throw new ArithmeticException("除数不能为零");
}
return left.interpret() / divisor;
}
}
// 表达式解析器
class ExpressionParser {
private Context context;
public ExpressionParser(Context context) {
this.context = context;
}
public Expression parse(String expression) {
// 简化的解析器,仅支持基本的四则运算
// 实际应用中需要更复杂的解析逻辑
return parseExpression(expression.replaceAll("\\s+", ""));
}
private Expression parseExpression(String expression) {
// 处理加法和减法(优先级最低)
int index = expression.lastIndexOf('+');
if (index != -1) {
Expression left = parseExpression(expression.substring(0, index));
Expression right = parseExpression(expression.substring(index + 1));
return new AddExpression(left, right);
}
index = expression.lastIndexOf('-');
if (index > 0) { // 确保不是负号
Expression left = parseExpression(expression.substring(0, index));
Expression right = parseExpression(expression.substring(index + 1));
return new SubtractExpression(left, right);
}
// 处理乘法和除法
index = expression.lastIndexOf('*');
if (index != -1) {
Expression left = parseExpression(expression.substring(0, index));
Expression right = parseExpression(expression.substring(index + 1));
return new MultiplyExpression(left, right);
}
index = expression.lastIndexOf('/');
if (index != -1) {
Expression left = parseExpression(expression.substring(0, index));
Expression right = parseExpression(expression.substring(index + 1));
return new DivideExpression(left, right);
}
// 处理括号
if (expression.startsWith("(") && expression.endsWith(")")) {
return parseExpression(expression.substring(1, expression.length() - 1));
}
// 处理数字
if (expression.matches("\\d+")) {
return new NumberExpression(Integer.parseInt(expression));
}
// 处理变量
if (expression.matches("[a-zA-Z_][a-zA-Z0-9_]*")) {
return new VariableExpression(expression);
}
throw new IllegalArgumentException("无法解析表达式: " + expression);
}
}
// 使用示例
public class MathExpressionDemo {
public static void main(String[] args) {
Context context = new Context();
context.setVariable("x", 10);
context.setVariable("y", 5);
context.setVariable("z", 2);
ExpressionParser parser = new ExpressionParser(context);
try {
// 测试各种表达式
System.out.println("=== 数学表达式解释器测试 ===");
Expression expr1 = parser.parse("10 + 5");
System.out.println("10 + 5 = " + expr1.interpret());
Expression expr2 = parser.parse("20 - 8");
System.out.println("20 - 8 = " + expr2.interpret());
Expression expr3 = parser.parse("6 * 7");
System.out.println("6 * 7 = " + expr3.interpret());
Expression expr4 = parser.parse("15 / 3");
System.out.println("15 / 3 = " + expr4.interpret());
Expression expr5 = parser.parse("x + y * z");
System.out.println("x + y * z = " + expr5.interpret(context));
Expression expr6 = parser.parse("(x + y) * z");
System.out.println("(x + y) * z = " + expr6.interpret(context));
Expression expr7 = parser.parse("x * y + z");
System.out.println("x * y + z = " + expr7.interpret(context));
} catch (Exception e) {
System.err.println("解析错误: " + e.getMessage());
}
}
// 重载interpret方法以支持上下文
private static int interpret(Expression expr, Context context) {
if (expr instanceof VariableExpression) {
return ((VariableExpression) expr).interpret(context);
} else {
return expr.interpret();
}
}
}
解释器模式的应用场景
- 正则表达式:Java中的Pattern类使用了解释器模式
- SQL解析:数据库系统中的SQL解析器
- 数学表达式:计算器应用中的表达式解析
- 配置文件解析:解析特定格式的配置文件
- 脚本语言:简单的脚本语言解释器
- 模板引擎:如JSP、Thymeleaf等模板引擎
解释器模式的优缺点
优点
- 可扩展性好:可以很容易地改变和扩展文法,因为该模式使用类来表示文法规则
- 容易实现:在语法树中的每个表达式节点类都有相似的结构,因此实现其文法较为容易
- 灵活性:可以使用面向对象的技术来解释执行语言,而不是使用过程式的技术
缺点
- 执行效率较低:解释器模式为每一个语法都定义了一个类,因此对于复杂的文法,可能产生大量的类,影响执行效率
- 维护困难:文法的修改需要修改大量的类,维护困难
- 适用范围有限:解释器模式一般适用于简单的文法,对于复杂的文法,维护和扩展都比较困难
解释器模式与其他模式的比较
与组合模式的区别
- 解释器模式:关注于解释语言中的句子
- 组合模式:关注于对象的组织结构
与策略模式的区别
- 解释器模式:通过语法树来解释句子
- 策略模式:通过封装算法来实现不同的策略
与访问者模式的区别
- 解释器模式:解释语言中的句子
- 访问者模式:在不改变元素类的前提下,为元素类添加新的操作
解释器模式的变体
1. 带缓存的解释器
// 带缓存的表达式解析器
class CachedExpressionParser {
private Context context;
private Map<String, Expression> cache = new HashMap<>();
public CachedExpressionParser(Context context) {
this.context = context;
}
public Expression parse(String expression) {
// 检查缓存
if (cache.containsKey(expression)) {
System.out.println("从缓存获取表达式: " + expression);
return cache.get(expression);
}
// 解析表达式
Expression expr = parseExpression(expression.replaceAll("\\s+", ""));
// 存入缓存
cache.put(expression, expr);
System.out.println("解析并缓存表达式: " + expression);
return expr;
}
private Expression parseExpression(String expression) {
// 简化的解析逻辑(与之前相同)
// ...
return new NumberExpression(0); // 简化实现
}
}
2. 带验证的解释器
// 带验证的表达式
interface ValidatingExpression extends Expression {
boolean validate(Context context);
}
// 带验证的变量表达式
class ValidatingVariableExpression implements ValidatingExpression {
private String name;
public ValidatingVariableExpression(String name) {
this.name = name;
}
@Override
public int interpret() {
throw new UnsupportedOperationException();
}
@Override
public int interpret(Context context) {
if (!validate(context)) {
throw new IllegalArgumentException("变量验证失败: " + name);
}
return context.getVariable(name);
}
@Override
public boolean validate(Context context) {
return context.hasVariable(name);
}
}
实际项目中的应用
// 布尔表达式解释器示例
// 抽象表达式
interface BooleanExpression {
boolean interpret(Context context);
}
// 上下文类
class Context {
private Map<String, Boolean> variables = new HashMap<>();
public void setVariable(String name, Boolean value) {
variables.put(name, value);
}
public Boolean getVariable(String name) {
return variables.get(name);
}
public boolean hasVariable(String name) {
return variables.containsKey(name);
}
}
// 布尔常量(终结符)
class BooleanConstant implements BooleanExpression {
private boolean value;
public BooleanConstant(boolean value) {
this.value = value;
}
@Override
public boolean interpret(Context context) {
return value;
}
}
// 变量表达式(终结符)
class VariableExpression implements BooleanExpression {
private String name;
public VariableExpression(String name) {
this.name = name;
}
@Override
public boolean interpret(Context context) {
if (!context.hasVariable(name)) {
throw new IllegalArgumentException("未定义的变量: " + name);
}
return context.getVariable(name);
}
}
// 与操作(非终结符)
class AndExpression implements BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public AndExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(Context context) {
return left.interpret(context) && right.interpret(context);
}
}
// 或操作(非终结符)
class OrExpression implements BooleanExpression {
private BooleanExpression left;
private BooleanExpression right;
public OrExpression(BooleanExpression left, BooleanExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(Context context) {
return left.interpret(context) || right.interpret(context);
}
}
// 非操作(非终结符)
class NotExpression implements BooleanExpression {
private BooleanExpression expression;
public NotExpression(BooleanExpression expression) {
this.expression = expression;
}
@Override
public boolean interpret(Context context) {
return !expression.interpret(context);
}
}
// 布尔表达式解析器
class BooleanExpressionParser {
private Context context;
public BooleanExpressionParser(Context context) {
this.context = context;
}
public BooleanExpression parse(String expression) {
return parseExpression(expression.trim());
}
private BooleanExpression parseExpression(String expression) {
// 处理括号
if (expression.startsWith("(") && expression.endsWith(")")) {
return parseExpression(expression.substring(1, expression.length() - 1));
}
// 处理NOT操作
if (expression.startsWith("!")) {
return new NotExpression(parseExpression(expression.substring(1).trim()));
}
// 处理OR操作
int orIndex = findOperator(expression, "||");
if (orIndex != -1) {
BooleanExpression left = parseExpression(expression.substring(0, orIndex).trim());
BooleanExpression right = parseExpression(expression.substring(orIndex + 2).trim());
return new OrExpression(left, right);
}
// 处理AND操作
int andIndex = findOperator(expression, "&&");
if (andIndex != -1) {
BooleanExpression left = parseExpression(expression.substring(0, andIndex).trim());
BooleanExpression right = parseExpression(expression.substring(andIndex + 2).trim());
return new AndExpression(left, right);
}
// 处理常量
if ("true".equalsIgnoreCase(expression)) {
return new BooleanConstant(true);
}
if ("false".equalsIgnoreCase(expression)) {
return new BooleanConstant(false);
}
// 处理变量
if (expression.matches("[a-zA-Z_][a-zA-Z0-9_]*")) {
return new VariableExpression(expression);
}
throw new IllegalArgumentException("无法解析布尔表达式: " + expression);
}
private int findOperator(String expression, String operator) {
int index = expression.indexOf(operator);
while (index != -1) {
// 检查是否在括号内
if (!isInParentheses(expression, index)) {
return index;
}
index = expression.indexOf(operator, index + 1);
}
return -1;
}
private boolean isInParentheses(String expression, int index) {
int openCount = 0;
for (int i = 0; i < index; i++) {
if (expression.charAt(i) == '(') {
openCount++;
} else if (expression.charAt(i) == ')') {
openCount--;
}
}
return openCount > 0;
}
}
// 使用示例
public class BooleanExpressionDemo {
public static void main(String[] args) {
Context context = new Context();
context.setVariable("a", true);
context.setVariable("b", false);
context.setVariable("c", true);
BooleanExpressionParser parser = new BooleanExpressionParser(context);
try {
System.out.println("=== 布尔表达式解释器测试 ===");
// 测试各种布尔表达式
BooleanExpression expr1 = parser.parse("true");
System.out.println("true = " + expr1.interpret(context));
BooleanExpression expr2 = parser.parse("false");
System.out.println("false = " + expr2.interpret(context));
BooleanExpression expr3 = parser.parse("a");
System.out.println("a = " + expr3.interpret(context));
BooleanExpression expr4 = parser.parse("a && b");
System.out.println("a && b = " + expr4.interpret(context));
BooleanExpression expr5 = parser.parse("a || b");
System.out.println("a || b = " + expr5.interpret(context));
BooleanExpression expr6 = parser.parse("!a");
System.out.println("!a = " + expr6.interpret(context));
BooleanExpression expr7 = parser.parse("a && (b || c)");
System.out.println("a && (b || c) = " + expr7.interpret(context));
BooleanExpression expr8 = parser.parse("!(a && b) || c");
System.out.println("!(a && b) || c = " + expr8.interpret(context));
} catch (Exception e) {
System.err.println("解析错误: " + e.getMessage());
}
}
}
// SQL WHERE子句解释器示例
// 抽象表达式
interface SqlExpression {
boolean evaluate(Map<String, Object> row);
}
// 上下文类
class SqlContext {
private List<Map<String, Object>> data;
public SqlContext(List<Map<String, Object>> data) {
this.data = data;
}
public List<Map<String, Object>> getData() {
return data;
}
}
// 相等比较表达式
class EqualExpression implements SqlExpression {
private String columnName;
private Object value;
public EqualExpression(String columnName, Object value) {
this.columnName = columnName;
this.value = value;
}
@Override
public boolean evaluate(Map<String, Object> row) {
Object columnValue = row.get(columnName);
if (columnValue == null && value == null) {
return true;
}
if (columnValue == null || value == null) {
return false;
}
return columnValue.equals(value);
}
}
// 大于比较表达式
class GreaterThanExpression implements SqlExpression {
private String columnName;
private Comparable value;
public GreaterThanExpression(String columnName, Comparable value) {
this.columnName = columnName;
this.value = value;
}
@Override
public boolean evaluate(Map<String, Object> row) {
Object columnValue = row.get(columnName);
if (columnValue instanceof Comparable) {
return ((Comparable) columnValue).compareTo(value) > 0;
}
return false;
}
}
// 小于比较表达式
class LessThanExpression implements SqlExpression {
private String columnName;
private Comparable value;
public LessThanExpression(String columnName, Comparable value) {
this.columnName = columnName;
this.value = value;
}
@Override
public boolean evaluate(Map<String, Object> row) {
Object columnValue = row.get(columnName);
if (columnValue instanceof Comparable) {
return ((Comparable) columnValue).compareTo(value) < 0;
}
return false;
}
}
// AND表达式
class AndSqlExpression implements SqlExpression {
private SqlExpression left;
private SqlExpression right;
public AndSqlExpression(SqlExpression left, SqlExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean evaluate(Map<String, Object> row) {
return left.evaluate(row) && right.evaluate(row);
}
}
// OR表达式
class OrSqlExpression implements SqlExpression {
private SqlExpression left;
private SqlExpression right;
public OrSqlExpression(SqlExpression left, SqlExpression right) {
this.left = left;
this.right = right;
}
@Override
public boolean evaluate(Map<String, Object> row) {
return left.evaluate(row) || right.evaluate(row);
}
}
// SQL解释器
class SqlInterpreter {
private SqlContext context;
public SqlInterpreter(SqlContext context) {
this.context = context;
}
public List<Map<String, Object>> executeQuery(String whereClause) {
SqlExpression expression = parseWhereClause(whereClause);
List<Map<String, Object>> result = new ArrayList<>();
for (Map<String, Object> row : context.getData()) {
if (expression.evaluate(row)) {
result.add(row);
}
}
return result;
}
private SqlExpression parseWhereClause(String whereClause) {
// 简化的解析器,仅支持基本的WHERE子句
// 实际应用中需要更复杂的解析逻辑
whereClause = whereClause.trim();
if (whereClause.startsWith("WHERE ")) {
whereClause = whereClause.substring(6).trim();
}
return parseExpression(whereClause);
}
private SqlExpression parseExpression(String expression) {
// 处理AND操作
int andIndex = expression.indexOf(" AND ");
if (andIndex != -1) {
SqlExpression left = parseExpression(expression.substring(0, andIndex));
SqlExpression right = parseExpression(expression.substring(andIndex + 5));
return new AndSqlExpression(left, right);
}
// 处理OR操作
int orIndex = expression.indexOf(" OR ");
if (orIndex != -1) {
SqlExpression left = parseExpression(expression.substring(0, orIndex));
SqlExpression right = parseExpression(expression.substring(orIndex + 4));
return new OrSqlExpression(left, right);
}
// 处理比较操作
if (expression.contains(" = ")) {
String[] parts = expression.split(" = ");
return new EqualExpression(parts[0].trim(), parts[1].trim().replace("'", ""));
}
if (expression.contains(" > ")) {
String[] parts = expression.split(" > ");
return new GreaterThanExpression(parts[0].trim(), Integer.parseInt(parts[1].trim()));
}
if (expression.contains(" < ")) {
String[] parts = expression.split(" < ");
return new LessThanExpression(parts[0].trim(), Integer.parseInt(parts[1].trim()));
}
throw new IllegalArgumentException("无法解析WHERE子句: " + expression);
}
}
// 使用示例
public class SqlInterpreterDemo {
public static void main(String[] args) {
// 创建测试数据
List<Map<String, Object>> data = new ArrayList<>();
Map<String, Object> row1 = new HashMap<>();
row1.put("name", "张三");
row1.put("age", 25);
row1.put("salary", 5000);
data.add(row1);
Map<String, Object> row2 = new HashMap<>();
row2.put("name", "李四");
row2.put("age", 30);
row2.put("salary", 8000);
data.add(row2);
Map<String, Object> row3 = new HashMap<>();
row3.put("name", "王五");
row3.put("age", 35);
row3.put("salary", 12000);
data.add(row3);
// 创建SQL解释器
SqlContext context = new SqlContext(data);
SqlInterpreter interpreter = new SqlInterpreter(context);
try {
System.out.println("=== SQL解释器测试 ===");
// 测试各种查询
System.out.println("1. 查询所有数据:");
List<Map<String, Object>> allData = interpreter.executeQuery("WHERE age > 0");
printResults(allData);
System.out.println("\n2. 查询年龄大于25的员工:");
List<Map<String, Object>> result1 = interpreter.executeQuery("WHERE age > 25");
printResults(result1);
System.out.println("\n3. 查询薪资大于6000的员工:");
List<Map<String, Object>> result2 = interpreter.executeQuery("WHERE salary > 6000");
printResults(result2);
System.out.println("\n4. 查询姓名为张三的员工:");
List<Map<String, Object>> result3 = interpreter.executeQuery("WHERE name = '张三'");
printResults(result3);
System.out.println("\n5. 查询年龄大于25且薪资大于6000的员工:");
List<Map<String, Object>> result4 = interpreter.executeQuery("WHERE age > 25 AND salary > 6000");
printResults(result4);
} catch (Exception e) {
System.err.println("查询错误: " + e.getMessage());
}
}
private static void printResults(List<Map<String, Object>> results) {
for (Map<String, Object> row : results) {
System.out.println(" " + row);
}
}
}
总结
解释器模式是一种行为型设计模式,它通过定义语言的文法表示和构建解释器来解释语言中的句子。在实际开发中,当我们需要处理特定领域语言时,解释器模式是一个很好的选择。
使用解释器模式的关键点:
- 识别出需要解释的语言和语法规则
- 定义抽象表达式接口
- 创建终结符表达式和非终结符表达式类
- 构建抽象语法树来表示语言中的句子
- 通过解释器来解释和执行句子
解释器模式的优点是可以灵活地改变和扩展文法,容易实现,但也需要注意执行效率较低和维护困难的问题。在现代Java开发中,解释器模式广泛应用于正则表达式、SQL解析、模板引擎、脚本语言等场景。