解释器设计模式全方位深度解析

4 阅读15分钟

一、模式定义与核心思想

解释器模式是一种行为设计模式,定义了一种语言的文法表示,并创建一个解释器来解释该语言中的句子。它主要用于处理领域特定语言(DSL) 的解析和求值。

核心思想:将语言文法表示为对象结构,通过遍历抽象语法树解释执行

  1. 将文法规则表示为类层次结构
  2. 每个文法规则对应一个表达式类
  3. 通过组合模式构建抽象语法树(AST)
  4. 遍历AST对表达式进行求值

二、Java代码实现

2.1 基础实现:布尔表达式解释器

java
java
下载
复制
import java.util.Map;
import java.util.HashMap;
import java.util.Stack;

// 1. 抽象表达式接口
public interface BooleanExpression {
    boolean interpret(Context context);
    
    // 默认方法:支持And/Or操作符
    default BooleanExpression and(BooleanExpression other) {
        return new AndExpression(this, other);
    }
    
    default BooleanExpression or(BooleanExpression other) {
        return new OrExpression(this, other);
    }
    
    default BooleanExpression not() {
        return new NotExpression(this);
    }
}

// 2. 上下文:存储变量值
public 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) {
        Boolean value = variables.get(name);
        if (value == null) {
            throw new IllegalArgumentException("未定义变量: " + name);
        }
        return value;
    }
    
    public boolean hasVariable(String name) {
        return variables.containsKey(name);
    }
}

// 3. 终结符表达式:变量
public class VariableExpression implements BooleanExpression {
    private String name;
    
    public VariableExpression(String name) {
        this.name = name;
    }
    
    @Override
    public boolean interpret(Context context) {
        return context.getVariable(name);
    }
    
    @Override
    public String toString() {
        return name;
    }
}

// 4. 终结符表达式:常量
public class ConstantExpression implements BooleanExpression {
    private boolean value;
    
    public ConstantExpression(boolean value) {
        this.value = value;
    }
    
    @Override
    public boolean interpret(Context context) {
        return value;
    }
    
    @Override
    public String toString() {
        return Boolean.toString(value);
    }
}

// 5. 非终结符表达式:与操作
public 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);
    }
    
    @Override
    public String toString() {
        return "(" + left + " AND " + right + ")";
    }
}

// 6. 非终结符表达式:或操作
public 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);
    }
    
    @Override
    public String toString() {
        return "(" + left + " OR " + right + ")";
    }
}

// 7. 非终结符表达式:非操作
public class NotExpression implements BooleanExpression {
    private BooleanExpression expression;
    
    public NotExpression(BooleanExpression expression) {
        this.expression = expression;
    }
    
    @Override
    public boolean interpret(Context context) {
        return !expression.interpret(context);
    }
    
    @Override
    public String toString() {
        return "NOT " + expression;
    }
}

// 8. 文法解析器
public class BooleanExpressionParser {
    // 支持的文法规则:
    // expression ::= term { ('OR' | '||') term }
    // term       ::= factor { ('AND' | '&&') factor }
    // factor     ::= variable | constant | '(' expression ')' | 'NOT' factor
    
    private String[] tokens;
    private int pos = 0;
    
    public BooleanExpression parse(String expression) {
        // 简单分词
        this.tokens = expression.replaceAll("\s+", " ")
                                .replaceAll("\(", " ( ")
                                .replaceAll("\)", " ) ")
                                .trim()
                                .split("\s+");
        this.pos = 0;
        return parseExpression();
    }
    
    private BooleanExpression parseExpression() {
        BooleanExpression expr = parseTerm();
        
        while (pos < tokens.length && (currentTokenIs("OR") || currentTokenIs("||"))) {
            consumeToken(); // 消耗OR操作符
            BooleanExpression right = parseTerm();
            expr = new OrExpression(expr, right);
        }
        
        return expr;
    }
    
    private BooleanExpression parseTerm() {
        BooleanExpression expr = parseFactor();
        
        while (pos < tokens.length && (currentTokenIs("AND") || currentTokenIs("&&"))) {
            consumeToken(); // 消耗AND操作符
            BooleanExpression right = parseFactor();
            expr = new AndExpression(expr, right);
        }
        
        return expr;
    }
    
    private BooleanExpression parseFactor() {
        if (currentTokenIs("(")) {
            consumeToken(); // 消耗左括号
            BooleanExpression expr = parseExpression();
            if (!currentTokenIs(")")) {
                throw new RuntimeException("期望右括号");
            }
            consumeToken(); // 消耗右括号
            return expr;
        } else if (currentTokenIs("NOT") || currentTokenIs("!")) {
            consumeToken(); // 消耗NOT操作符
            BooleanExpression expr = parseFactor();
            return new NotExpression(expr);
        } else if (currentTokenIs("TRUE") || currentTokenIs("FALSE")) {
            boolean value = Boolean.parseBoolean(consumeToken());
            return new ConstantExpression(value);
        } else {
            // 假设是变量
            String varName = consumeToken();
            return new VariableExpression(varName);
        }
    }
    
    private String currentToken() {
        if (pos < tokens.length) {
            return tokens[pos];
        }
        return null;
    }
    
    private boolean currentTokenIs(String expected) {
        String token = currentToken();
        return token != null && token.equals(expected);
    }
    
    private String consumeToken() {
        if (pos < tokens.length) {
            return tokens[pos++];
        }
        throw new RuntimeException("意外的输入结束");
    }
}

// 9. 客户端使用
public class BooleanInterpreterDemo {
    public static void main(String[] args) {
        // 创建上下文并设置变量值
        Context context = new Context();
        context.setVariable("A", true);
        context.setVariable("B", false);
        context.setVariable("C", true);
        context.setVariable("D", false);
        
        // 方法1:使用API直接构建表达式
        System.out.println("=== 方法1: 直接构建表达式 ===");
        BooleanExpression expr1 = new VariableExpression("A")
            .and(new VariableExpression("B").or(new VariableExpression("C")))
            .and(new NotExpression(new VariableExpression("D")));
        
        System.out.println("表达式: " + expr1);
        System.out.println("结果: " + expr1.interpret(context));
        
        // 方法2:使用解析器解析字符串表达式
        System.out.println("\n=== 方法2: 解析字符串表达式 ===");
        BooleanExpressionParser parser = new BooleanExpressionParser();
        
        String[] expressions = {
            "A AND B",
            "A OR B",
            "A AND (B OR C)",
            "NOT A AND (B OR C)",
            "(A AND B) OR (C AND D)",
            "A AND B AND C AND NOT D",
            "TRUE AND (FALSE OR A)"
        };
        
        for (String exprStr : expressions) {
            try {
                BooleanExpression expr = parser.parse(exprStr);
                System.out.println("表达式: " + exprStr);
                System.out.println("解析为: " + expr);
                System.out.println("结果: " + expr.interpret(context));
                System.out.println("---");
            } catch (Exception e) {
                System.out.println("解析失败: " + exprStr + " - " + e.getMessage());
            }
        }
        
        // 复杂示例
        System.out.println("\n=== 复杂示例: 规则引擎 ===");
        // 定义业务规则:用户年龄>18 AND (是VIP OR 消费金额>1000) AND NOT 黑名单用户
        Context userContext = new Context();
        userContext.setVariable("age_over_18", true);
        userContext.setVariable("is_vip", false);
        userContext.setVariable("purchase_over_1000", true);
        userContext.setVariable("is_blacklisted", false);
        
        String rule = "age_over_18 AND (is_vip OR purchase_over_1000) AND NOT is_blacklisted";
        BooleanExpression ruleExpr = parser.parse(rule);
        System.out.println("规则: " + rule);
        System.out.println("解析: " + ruleExpr);
        System.out.println("用户是否合格: " + ruleExpr.interpret(userContext));
    }
}

2.2 进阶示例:SQL条件表达式解释器

java
java
下载
复制
import java.util.List;
import java.util.ArrayList;
import java.util.function.Predicate;

// 1. SQL表达式接口
public interface SQLExpression<T> {
    Predicate<T> interpret();
    String toSQL();
}

// 2. 数据库记录泛型上下文
public class DatabaseContext<T> {
    private List<T> records = new ArrayList<>();
    private Class<T> recordType;
    
    public DatabaseContext(Class<T> recordType) {
        this.recordType = recordType;
    }
    
    public void addRecord(T record) {
        records.add(record);
    }
    
    public List<T> query(SQLExpression<T> expression) {
        Predicate<T> predicate = expression.interpret();
        List<T> result = new ArrayList<>();
        for (T record : records) {
            if (predicate.test(record)) {
                result.add(record);
            }
        }
        return result;
    }
}

// 3. 字段表达式
public class FieldExpression<T, R> implements SQLExpression<T> {
    private String fieldName;
    private ValueExpression<R> value;
    private Operator operator;
    
    public enum Operator {
        EQ("="), NE("<>"), GT(">"), LT("<"), GE(">="), LE("<="),
        LIKE("LIKE"), IN("IN"), NOT_IN("NOT IN");
        
        private final String symbol;
        
        Operator(String symbol) {
            this.symbol = symbol;
        }
        
        public String getSymbol() {
            return symbol;
        }
    }
    
    public FieldExpression(String fieldName, Operator operator, ValueExpression<R> value) {
        this.fieldName = fieldName;
        this.operator = operator;
        this.value = value;
    }
    
    @Override
    public Predicate<T> interpret() {
        R constValue = value.getValue();
        return record -> {
            try {
                // 通过反射获取字段值
                var field = record.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                R fieldValue = (R) field.get(record);
                
                switch (operator) {
                    case EQ: return fieldValue.equals(constValue);
                    case NE: return !fieldValue.equals(constValue);
                    case GT: return ((Comparable)fieldValue).compareTo(constValue) > 0;
                    case LT: return ((Comparable)fieldValue).compareTo(constValue) < 0;
                    case GE: return ((Comparable)fieldValue).compareTo(constValue) >= 0;
                    case LE: return ((Comparable)fieldValue).compareTo(constValue) <= 0;
                    case LIKE: 
                        if (fieldValue instanceof String && constValue instanceof String) {
                            String pattern = ((String)constValue).replace("%", ".*");
                            return ((String)fieldValue).matches(pattern);
                        }
                        return false;
                    default: return false;
                }
            } catch (Exception e) {
                return false;
            }
        };
    }
    
    @Override
    public String toSQL() {
        return fieldName + " " + operator.getSymbol() + " " + value.toSQL();
    }
}

// 4. 值表达式
public class ValueExpression<T> {
    private T value;
    
    public ValueExpression(T value) {
        this.value = value;
    }
    
    public T getValue() {
        return value;
    }
    
    public String toSQL() {
        if (value instanceof String) {
            return "'" + value + "'";
        } else if (value instanceof Number) {
            return value.toString();
        } else if (value instanceof Boolean) {
            return (Boolean)value ? "TRUE" : "FALSE";
        } else {
            return value.toString();
        }
    }
}

// 5. 逻辑表达式
public class AndExpression<T> implements SQLExpression<T> {
    private SQLExpression<T> left;
    private SQLExpression<T> right;
    
    public AndExpression(SQLExpression<T> left, SQLExpression<T> right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public Predicate<T> interpret() {
        Predicate<T> leftPredicate = left.interpret();
        Predicate<T> rightPredicate = right.interpret();
        return leftPredicate.and(rightPredicate);
    }
    
    @Override
    public String toSQL() {
        return "(" + left.toSQL() + " AND " + right.toSQL() + ")";
    }
}

public class OrExpression<T> implements SQLExpression<T> {
    private SQLExpression<T> left;
    private SQLExpression<T> right;
    
    public OrExpression(SQLExpression<T> left, SQLExpression<T> right) {
        this.left = left;
        this.right = right;
    }
    
    @Override
    public Predicate<T> interpret() {
        Predicate<T> leftPredicate = left.interpret();
        Predicate<T> rightPredicate = right.interpret();
        return leftPredicate.or(rightPredicate);
    }
    
    @Override
    public String toSQL() {
        return "(" + left.toSQL() + " OR " + right.toSQL() + ")";
    }
}

public class NotExpression<T> implements SQLExpression<T> {
    private SQLExpression<T> expression;
    
    public NotExpression(SQLExpression<T> expression) {
        this.expression = expression;
    }
    
    @Override
    public Predicate<T> interpret() {
        Predicate<T> predicate = expression.interpret();
        return predicate.negate();
    }
    
    @Override
    public String toSQL() {
        return "NOT " + expression.toSQL();
    }
}

// 6. 实体类
public class User {
    private int id;
    private String name;
    private int age;
    private boolean active;
    private String email;
    
    public User(int id, String name, int age, boolean active, String email) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.active = active;
        this.email = email;
    }
    
    // Getters
    public int getId() { return id; }
    public String getName() { return name; }
    public int getAge() { return age; }
    public boolean isActive() { return active; }
    public String getEmail() { return email; }
    
    @Override
    public String toString() {
        return String.format("User{id=%d, name='%s', age=%d, active=%s, email='%s'}", 
            id, name, age, active, email);
    }
}

// 7. SQL解释器使用示例
public class SQLInterpreterDemo {
    public static void main(String[] args) throws Exception {
        // 创建数据库上下文
        DatabaseContext<User> db = new DatabaseContext<>(User.class);
        
        // 添加测试数据
        db.addRecord(new User(1, "张三", 25, true, "zhangsan@example.com"));
        db.addRecord(new User(2, "李四", 18, true, "lisi@example.com"));
        db.addRecord(new User(3, "王五", 30, false, "wangwu@example.com"));
        db.addRecord(new User(4, "赵六", 22, true, "zhaoliu@example.com"));
        db.addRecord(new User(5, "孙七", 35, true, "sunqi@example.com"));
        
        // 构建SQL查询表达式
        // 查询条件: age >= 20 AND active = true AND (name LIKE '张%' OR email LIKE '%example%')
        
        // 手动构建表达式树
        SQLExpression<User> ageCondition = new FieldExpression<>(
            "age", FieldExpression.Operator.GE, new ValueExpression<>(20)
        );
        
        SQLExpression<User> activeCondition = new FieldExpression<>(
            "active", FieldExpression.Operator.EQ, new ValueExpression<>(true)
        );
        
        SQLExpression<User> nameCondition = new FieldExpression<>(
            "name", FieldExpression.Operator.LIKE, new ValueExpression<>("张%")
        );
        
        SQLExpression<User> emailCondition = new FieldExpression<>(
            "email", FieldExpression.Operator.LIKE, new ValueExpression<>("%example%")
        );
        
        SQLExpression<User> orCondition = new OrExpression<>(nameCondition, emailCondition);
        SQLExpression<User> fullCondition = new AndExpression<>(
            new AndExpression<>(ageCondition, activeCondition),
            orCondition
        );
        
        // 执行查询
        System.out.println("=== SQL条件查询 ===");
        System.out.println("SQL: " + fullCondition.toSQL());
        System.out.println("\n查询结果:");
        
        List<User> results = db.query(fullCondition);
        for (User user : results) {
            System.out.println(user);
        }
        
        // 复杂的条件组合
        System.out.println("\n=== 复杂条件组合 ===");
        // (age > 18 AND age < 30) OR (name = '王五')
        SQLExpression<User> ageLower = new FieldExpression<>(
            "age", FieldExpression.Operator.GT, new ValueExpression<>(18)
        );
        
        SQLExpression<User> ageUpper = new FieldExpression<>(
            "age", FieldExpression.Operator.LT, new ValueExpression<>(30)
        );
        
        SQLExpression<User> nameEq = new FieldExpression<>(
            "name", FieldExpression.Operator.EQ, new ValueExpression<>("王五")
        );
        
        SQLExpression<User> ageRange = new AndExpression<>(ageLower, ageUpper);
        SQLExpression<User> complexCondition = new OrExpression<>(ageRange, nameEq);
        
        System.out.println("SQL: " + complexCondition.toSQL());
        System.out.println("\n查询结果:");
        
        List<User> complexResults = db.query(complexCondition);
        for (User user : complexResults) {
            System.out.println(user);
        }
        
        // 使用流畅API构建表达式
        System.out.println("\n=== 流畅API构建 ===");
        SQLExpression<User> fluentCondition = 
            new AndExpression<>(
                new FieldExpression<>("age", FieldExpression.Operator.GE, new ValueExpression<>(20)),
                new NotExpression<>(
                    new FieldExpression<>("active", FieldExpression.Operator.EQ, new ValueExpression<>(false))
                )
            );
        
        System.out.println("SQL: " + fluentCondition.toSQL());
        System.out.println("\n查询结果:");
        List<User> fluentResults = db.query(fluentCondition);
        for (User user : fluentResults) {
            System.out.println(user);
        }
    }
}

三、应用场景

3.1 典型应用场景

  1. 编程语言编译器/解释器

    • 脚本语言解释器
    • 正则表达式引擎
    • SQL查询解析器
    • 模板引擎
  2. 业务规则引擎

    • 风控规则评估
    • 促销规则计算
    • 工作流条件判断
    • 决策表/决策树
  3. 配置和查询语言

    • 日志查询语言(如Log4j的Filter)
    • 数据查询语言
    • 配置文件解析
    • 权限表达式语言
  4. 数学表达式计算

    • 科学计算器
    • 公式计算引擎
    • 统计表达式
    • 金融计算
  5. 通信协议解析

    • 自定义协议解析
    • 数据格式转换
    • 命令解释器
    • 消息路由规则
  6. 领域特定语言(DSL)

    • 游戏脚本语言
    • 测试用例描述语言
    • 工作流定义语言
    • 报表定义语言

3.2 使用时机判断

  • ✅ 需要解释执行一种简单的语言
  • ✅ 语言的文法比较简单,易于表示
  • ✅ 执行效率不是首要考虑因素
  • ✅ 语言可能频繁变化或扩展
  • ✅ 已有现成的文法表示工具不适用
  • ✅ 希望将语言解析与执行逻辑分离

四、优缺点分析

4.1 优点

  1. 易于扩展文法:新增文法规则只需添加新的表达式类
  2. 易于实现语言:文法规则的类层次结构清晰
  3. 支持多种解释:同一语法树可支持不同的解释方式
  4. 符合开闭原则:新增表达式类型无需修改现有代码
  5. 简化复杂语法:将复杂语法分解为简单表达式
  6. 良好的可维护性:每个表达式类职责单一,易于测试

4.2 缺点

  1. 类数量爆炸:复杂的文法会导致大量类文件
  2. 执行效率较低:递归调用和对象创建开销大
  3. 难以维护复杂文法:复杂文法导致类结构复杂
  4. 不适用于复杂语言:对于复杂编程语言,应使用专业解析器
  5. 调试困难:解释过程涉及大量递归,调试困难
  6. 学习曲线陡峭:需要理解文法理论和递归结构

五、模式变体与改进

5.1 模式变体

java
java
下载
复制
// 变体1:带缓存的解释器
public class CachedExpression implements BooleanExpression {
    private BooleanExpression expression;
    private Map<Context, Boolean> cache = new HashMap<>();
    
    public CachedExpression(BooleanExpression expression) {
        this.expression = expression;
    }
    
    @Override
    public boolean interpret(Context context) {
        return cache.computeIfAbsent(context, ctx -> expression.interpret(ctx));
    }
}

// 变体2:可变的解释器
public class MutableExpression implements BooleanExpression {
    private BooleanExpression expression;
    
    public void setExpression(BooleanExpression expression) {
        this.expression = expression;
    }
    
    @Override
    public boolean interpret(Context context) {
        if (expression == null) {
            throw new IllegalStateException("表达式未设置");
        }
        return expression.interpret(context);
    }
}

// 变体3:解释器组合器
public class ExpressionCombinator {
    public static BooleanExpression and(BooleanExpression... expressions) {
        if (expressions.length == 0) return new ConstantExpression(true);
        if (expressions.length == 1) return expressions[0];
        
        BooleanExpression result = expressions[0];
        for (int i = 1; i < expressions.length; i++) {
            result = new AndExpression(result, expressions[i]);
        }
        return result;
    }
    
    public static BooleanExpression or(BooleanExpression... expressions) {
        if (expressions.length == 0) return new ConstantExpression(false);
        if (expressions.length == 1) return expressions[0];
        
        BooleanExpression result = expressions[0];
        for (int i = 1; i < expressions.length; i++) {
            result = new OrExpression(result, expressions[i]);
        }
        return result;
    }
}

5.2 结合其他模式

java
java
下载
复制
// 结合访问者模式:遍历语法树
public class ExpressionPrinter implements ExpressionVisitor {
    private StringBuilder result = new StringBuilder();
    
    public void visit(VariableExpression expr) {
        result.append(expr.getName());
    }
    
    public void visit(AndExpression expr) {
        result.append("(");
        expr.getLeft().accept(this);
        result.append(" AND ");
        expr.getRight().accept(this);
        result.append(")");
    }
    
    public String getResult() {
        return result.toString();
    }
}

// 结合享元模式:共享表达式
public class ExpressionFlyweightFactory {
    private Map<String, BooleanExpression> variables = new HashMap<>();
    private Map<Boolean, BooleanExpression> constants = new HashMap<>();
    
    public BooleanExpression getVariable(String name) {
        return variables.computeIfAbsent(name, VariableExpression::new);
    }
    
    public BooleanExpression getConstant(boolean value) {
        return constants.computeIfAbsent(value, ConstantExpression::new);
    }
}

// 结合建造者模式:流畅API
public class ExpressionBuilder {
    private BooleanExpression current;
    
    public ExpressionBuilder variable(String name) {
        current = new VariableExpression(name);
        return this;
    }
    
    public ExpressionBuilder constant(boolean value) {
        current = new ConstantExpression(value);
        return this;
    }
    
    public ExpressionBuilder and(String name) {
        current = new AndExpression(current, new VariableExpression(name));
        return this;
    }
    
    public ExpressionBuilder and(boolean value) {
        current = new AndExpression(current, new ConstantExpression(value));
        return this;
    }
    
    public BooleanExpression build() {
        return current;
    }
}

六、注意事项与最佳实践

6.1 使用注意事项

  1. 性能优化

    java
    java
    下载
    复制
    public class OptimizedInterpreter {
        // 1. 表达式预编译
        public static BooleanExpression compile(String expression) {
            // 解析并优化表达式
            BooleanExpression parsed = parse(expression);
            return optimize(parsed);
        }
    
        // 2. 常量折叠优化
        private static BooleanExpression optimize(BooleanExpression expr) {
            if (expr instanceof AndExpression) {
                AndExpression and = (AndExpression) expr;
                BooleanExpression left = optimize(and.getLeft());
                BooleanExpression right = optimize(and.getRight());
    
                // 常量折叠: true AND x -> x, false AND x -> false
                if (left instanceof ConstantExpression) {
                    boolean leftVal = ((ConstantExpression) left).interpret(null);
                    if (!leftVal) return new ConstantExpression(false);
                    if (right instanceof ConstantExpression) {
                        return new ConstantExpression(((ConstantExpression) right).interpret(null));
                    }
                    return right;
                }
                if (right instanceof ConstantExpression) {
                    boolean rightVal = ((ConstantExpression) right).interpret(null);
                    if (!rightVal) return new ConstantExpression(false);
                    return left;
                }
                return new AndExpression(left, right);
            }
            return expr;
        }
    
        // 3. 解释器缓存
        private static class CachedInterpreter {
            private Map<Context, Map<BooleanExpression, Boolean>> cache = new HashMap<>();
    
            public boolean interpret(Context context, BooleanExpression expr) {
                return cache.computeIfAbsent(context, k -> new HashMap<>())
                           .computeIfAbsent(expr, e -> expr.interpret(context));
            }
        }
    }
    
  2. 错误处理

    java
    java
    下载
    复制
    public class SafeExpressionParser {
        public BooleanExpression safeParse(String input) {
            try {
                return parse(input);
            } catch (Exception e) {
                // 提供友好的错误信息
                System.err.println("解析失败: " + input);
                System.err.println("错误: " + e.getMessage());
    
                // 尝试恢复或返回默认表达式
                return new ConstantExpression(false);
            }
        }
    
        public BooleanExpression parseWithValidation(String input) {
            BooleanExpression expr = parse(input);
            validate(expr);
            return expr;
        }
    
        private void validate(BooleanExpression expr) {
            // 验证表达式是否有效
            Set<String> variables = collectVariables(expr);
            for (String var : variables) {
                if (!isValidVariableName(var)) {
                    throw new IllegalArgumentException("无效的变量名: " + var);
                }
            }
        }
    }
    
  3. 线程安全

    java
    java
    下载
    复制
    public class ThreadSafeInterpreter {
        private final Map<Context, Boolean> cache = new ConcurrentHashMap<>();
    
        public boolean interpret(Context context, BooleanExpression expr) {
            String key = createKey(context, expr);
            return cache.computeIfAbsent(key, k -> expr.interpret(context));
        }
    
        private String createKey(Context context, BooleanExpression expr) {
            return expr.toString() + "@" + System.identityHashCode(context);
        }
    }
    

6.2 最佳实践

  1. 保持表达式不可变

    java
    java
    下载
    复制
    public final class ImmutableExpression implements BooleanExpression {
        private final BooleanExpression left;
        private final BooleanExpression right;
    
        public ImmutableExpression(BooleanExpression left, BooleanExpression right) {
            this.left = left;
            this.right = right;
        }
    
        // 不提供setter方法
    }
    
  2. 支持表达式序列化

    java
    java
    下载
    复制
    public interface SerializableExpression extends BooleanExpression, Serializable {
        // 标记接口,支持表达式序列化
    }
    
    public class SerializableAndExpression implements SerializableExpression {
        private final SerializableExpression left;
        private final SerializableExpression right;
    
        // 序列化支持
        private static final long serialVersionUID = 1L;
    }
    
  3. 提供表达式遍历支持

    java
    java
    下载
    复制
    public interface TraversableExpression extends BooleanExpression {
        void accept(ExpressionVisitor visitor);
        List<BooleanExpression> getChildren();
    }
    
    public class ExpressionUtils {
        public static List<String> collectVariables(BooleanExpression expr) {
            List<String> variables = new ArrayList<>();
            collectVariables(expr, variables);
            return variables;
        }
    
        private static void collectVariables(BooleanExpression expr, List<String> variables) {
            if (expr instanceof VariableExpression) {
                variables.add(((VariableExpression) expr).getName());
            } else if (expr instanceof BinaryExpression) {
                BinaryExpression binary = (BinaryExpression) expr;
                collectVariables(binary.getLeft(), variables);
                collectVariables(binary.getRight(), variables);
            } else if (expr instanceof NotExpression) {
                collectVariables(((NotExpression) expr).getExpression(), variables);
            }
        }
    }
    
  4. 实现表达式化简

    java
    java
    下载
    复制
    public class ExpressionSimplifier {
        public static BooleanExpression simplify(BooleanExpression expr) {
            if (expr instanceof AndExpression) {
                AndExpression and = (AndExpression) expr;
                BooleanExpression left = simplify(and.getLeft());
                BooleanExpression right = simplify(and.getRight());
    
                // 恒等律: A AND true = A
                if (isConstantTrue(right)) return left;
                if (isConstantTrue(left)) return right;
    
                // 零律: A AND false = false
                if (isConstantFalse(left) || isConstantFalse(right)) {
                    return new ConstantExpression(false);
                }
    
                // 幂等律: A AND A = A
                if (left.equals(right)) return left;
    
                return new AndExpression(left, right);
            }
            return expr;
        }
    }
    

七、替代方案与相关模式

  1. 访问者模式

    • 区别:访问者模式分离算法与结构,解释器模式实现语言文法
    • 选择:处理已有数据结构用访问者,处理自定义语言用解释器
  2. 组合模式

    • 关系:解释器模式通常使用组合模式构建语法树
    • 区别:组合模式关注部分-整体结构,解释器关注语言解释
  3. 策略模式

    • 区别:策略模式封装算法,解释器模式封装文法规则
    • 选择:算法选择用策略,语言解释用解释器
  4. 模板方法模式

    • 区别:模板方法定义算法骨架,解释器定义语言文法
    • 选择:算法步骤固定用模板方法,语言解释用解释器
  5. 使用现有解析器生成工具

    • ANTLR, JavaCC, Bison, Yacc
    • 对于复杂语言,使用这些工具比手写解释器更高效
    • 选择标准:语言复杂度、性能要求、开发时间
  6. 使用脚本语言引擎

    • JavaScript引擎(Nashorn, GraalVM)
    • Python引擎(Jython)
    • Lua引擎(Luaj)
    • 当需要完整编程语言功能时,嵌入现有引擎更合适

八、实际应用建议

8.1 何时使用解释器模式

  1. 实现简单领域特定语言(DSL)
  2. 需要可配置的业务规则
  3. 实现查询或过滤语言
  4. 构建表达式计算器
  5. 实现模板引擎或脚本语言

8.2 何时避免解释器模式

  1. 语言文法非常复杂
  2. 对性能要求极高
  3. 已有成熟的解析器生成工具
  4. 只需要简单字符串处理
  5. 语言频繁变化且结构不稳定

8.3 性能优化建议

  1. 预编译表达式:解析一次,多次执行
  2. 缓存解释结果:相同输入缓存结果
  3. 使用字节码生成:将表达式编译为字节码
  4. 优化数据结构:使用数组而非链表存储语法树
  5. 使用栈机:将语法树转换为字节码,用栈机执行

8.4 可扩展性设计

  1. 插件化文法:支持动态添加文法规则
  2. 多种后端:支持解释执行和编译执行
  3. 语法高亮:为表达式提供语法高亮支持
  4. 调试支持:提供单步执行和断点功能
  5. 性能分析:收集表达式执行统计信息

九、现代替代方案

java
java
下载
复制
// 使用函数式接口和Lambda
public class FunctionalInterpreter {
    @FunctionalInterface
    public interface Expression {
        boolean evaluate(Context context);
    }
    
    public static Expression parseFunctional(String expr) {
        // 使用Lambda表达式构建
        Context context = new Context();
        return ctx -> {
            // 动态编译和执行
            // 实际实现可使用动态编译或解释执行
            return evaluateExpression(expr, ctx);
        };
    }
    
    // 使用Java动态编译
    public static Expression compileToJava(String expr) throws Exception {
        String className = "DynamicExpression";
        String source = "public class " + className + " implements java.util.function.Predicate<Context> {" +
                       "    public boolean test(Context ctx) {" +
                       "        return " + expr + ";" +
                       "    }" +
                       "}";
        
        // 使用JavaCompiler动态编译
        // 返回编译后的Predicate
        return null;
    }
}

// 使用现有表达式引擎
public class ExistingEngineExample {
    public static void main(String[] args) throws Exception {
        // 1. Spring Expression Language (SpEL)
        // ExpressionParser parser = new SpelExpressionParser();
        // Expression exp = parser.parseExpression("name == '张三' && age > 18");
        
        // 2. MVEL
        // Map<String, Object> vars = new HashMap<>();
        // vars.put("name", "张三");
        // vars.put("age", 20);
        // Boolean result = (Boolean) MVEL.eval("name == '张三' && age > 18", vars);
        
        // 3. OGNL
        // Object value = Ognl.getValue("name", context);
        
        // 4. JEXL
        // JexlEngine jexl = new JexlBuilder().create();
        // JexlExpression e = jexl.createExpression("x + y * z");
    }
}

总结

解释器模式是实现领域特定语言的经典模式,特别适用于需要解释执行简单语言的场景。它将文法规则表示为对象结构,通过组合模式构建抽象语法树,然后遍历语法树进行求值。

关键价值:在需要灵活、可扩展的语言处理能力,且文法相对简单的场景中,解释器模式提供了一种清晰、面向对象的解决方案。它使得语言扩展变得容易,符合开闭原则,但需注意避免过度设计。

重要权衡

  • 对于简单文法,解释器模式简洁优雅
  • 对于复杂文法,应使用专业解析器生成工具
  • 在性能敏感场景,考虑预编译或使用现有引擎
  • 在可维护性和性能之间找到平衡点

在实际应用中,应根据具体需求评估是否需要实现完整的解释器。对于许多场景,使用现有表达式引擎(如SpEL、MVEL等)可能是更高效的选择。但当需要完全控制语言特性、有特定优化需求或学习目的时,实现自定义解释器仍然是合理的选择。