【设计模式手册014】解释器模式 - 语言解释的优雅实现

设计模式手册014:解释器模式 - 语言解释的优雅实现

本文是「设计模式手册」系列第014篇,我们将深入探讨解释器模式,这种模式给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

1. 场景:我们为何需要解释器模式?

在软件开发中,我们有时需要解释和执行特定语法或规则的表达式:

  • 数学表达式计算:解析和计算"1 + 2 * 3"这样的表达式
  • 规则引擎:处理业务规则如"年龄 > 18 AND 信用分 > 600"
  • 查询语言:解析SQL查询条件"WHERE name = 'John' AND age > 25"
  • 配置文件解析:处理复杂的配置语法
  • 领域特定语言(DSL):为特定领域创建专用语言

传统做法的困境

java 复制代码
// 硬编码的表达式解析 - 难以维护和扩展
public class SimpleExpressionCalculator {
    public static int calculate(String expression) {
        // 简单的加减法解析
        if (expression.contains("+")) {
            String[] parts = expression.split("\\+");
            return Integer.parseInt(parts[0].trim()) + Integer.parseInt(parts[1].trim());
        } else if (expression.contains("-")) {
            String[] parts = expression.split("-");
            return Integer.parseInt(parts[0].trim()) - Integer.parseInt(parts[1].trim());
        } else if (expression.contains("*")) {
            String[] parts = expression.split("\\*");
            return Integer.parseInt(parts[0].trim()) * Integer.parseInt(parts[1].trim());
        } else if (expression.contains("/")) {
            String[] parts = expression.split("/");
            return Integer.parseInt(parts[0].trim()) / Integer.parseInt(parts[1].trim());
        }
        
        // 如果表达式更复杂,比如 "1 + 2 * 3",这种简单解析就会出错
        throw new IllegalArgumentException("不支持的表达式: " + expression);
    }
    
    // 问题:无法处理复杂的嵌套表达式
    // 问题:每增加一种操作符就要修改代码
    // 问题:没有考虑运算符优先级
}

// 使用示例
public class TraditionalExpression {
    public static void main(String[] args) {
        System.out.println(SimpleExpressionCalculator.calculate("1 + 2")); // 3
        System.out.println(SimpleExpressionCalculator.calculate("5 - 3")); // 2
        
        // 这个会得到错误结果,因为简单分割无法处理运算符优先级
        // System.out.println(SimpleExpressionCalculator.calculate("1 + 2 * 3")); // 错误!
    }
}

这种实现的痛点

  • 硬编码解析逻辑:表达式语法变化时需要修改代码
  • 无法处理复杂语法:嵌套表达式、运算符优先级等
  • 违反开闭原则:新增语法元素需要修改现有代码
  • 难以维护:解析逻辑复杂且难以理解

2. 解释器模式:定义与本质

2.1 模式定义

解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

2.2 核心角色

java 复制代码
// 抽象表达式:声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享
public interface Expression {
    int interpret(Map<String, Integer> context);
}

// 终结符表达式:实现与文法中的终结符相关联的解释操作
public 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 int interpret(Map<String, Integer> context) {
        return number;
    }
}

// 变量表达式
public class VariableExpression implements Expression {
    private String variableName;
    
    public VariableExpression(String variableName) {
        this.variableName = variableName;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        Integer value = context.get(variableName);
        if (value == null) {
            throw new IllegalArgumentException("变量未定义: " + variableName);
        }
        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(Map<String, Integer> context) {
        return left.interpret(context) + right.interpret(context);
    }
}

// 非终结符表达式 - 减法运算
public 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(Map<String, Integer> 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(Map<String, Integer> context) {
        return left.interpret(context) * right.interpret(context);
    }
}

// 非终结符表达式 - 除法运算
public 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(Map<String, Integer> context) {
        int divisor = right.interpret(context);
        if (divisor == 0) {
            throw new ArithmeticException("除零错误");
        }
        return left.interpret(context) / divisor;
    }
}

3. 深入理解:解释器模式的多维视角

3.1 第一重:抽象语法树(AST)的构建

核心概念:解释器模式的核心是构建抽象语法树来表示语言的语法结构

java 复制代码
// 表达式构建器 - 用于构建抽象语法树
public class ExpressionBuilder {
    public static Expression build(String expression) {
        // 移除所有空格
        expression = expression.replaceAll("\\s+", "");
        
        // 处理括号表达式
        return parseExpression(expression);
    }
    
    private static Expression parseExpression(String expr) {
        // 查找最低优先级的操作符(从右向左查找,因为左结合性)
        int index = findLowestPriorityOperator(expr);
        
        if (index != -1) {
            char operator = expr.charAt(index);
            Expression left = parseExpression(expr.substring(0, index));
            Expression right = parseExpression(expr.substring(index + 1));
            
            switch (operator) {
                case '+': return new AddExpression(left, right);
                case '-': return new SubtractExpression(left, right);
                case '*': return new MultiplyExpression(left, right);
                case '/': return new DivideExpression(left, right);
                default: throw new IllegalArgumentException("未知操作符: " + operator);
            }
        }
        
        // 如果是数字
        if (expr.matches("\\d+")) {
            return new NumberExpression(expr);
        }
        
        // 如果是变量
        if (expr.matches("[a-zA-Z_][a-zA-Z_0-9]*")) {
            return new VariableExpression(expr);
        }
        
        // 如果是括号表达式
        if (expr.startsWith("(") && expr.endsWith(")")) {
            return parseExpression(expr.substring(1, expr.length() - 1));
        }
        
        throw new IllegalArgumentException("无法解析的表达式: " + expr);
    }
    
    private static int findLowestPriorityOperator(String expr) {
        int parenCount = 0;
        int index = -1;
        int lowestPriority = Integer.MAX_VALUE;
        
        // 从右向左扫描,找到优先级最低的操作符
        for (int i = expr.length() - 1; i >= 0; i--) {
            char c = expr.charAt(i);
            
            if (c == ')') parenCount++;
            else if (c == '(') parenCount--;
            
            if (parenCount == 0) {
                int priority = getOperatorPriority(c);
                if (priority != -1 && priority < lowestPriority) {
                    lowestPriority = priority;
                    index = i;
                }
            }
        }
        
        return index;
    }
    
    private static int getOperatorPriority(char operator) {
        switch (operator) {
            case '+': 
            case '-': return 1;  // 低优先级
            case '*': 
            case '/': return 2;  // 高优先级
            default: return -1;  // 不是操作符
        }
    }
}

// 使用示例
public class ExpressionTreeDemo {
    public static void main(String[] args) {
        // 构建表达式: (a + b) * c - 10
        Expression expression = ExpressionBuilder.build("(a + b) * c - 10");
        
        // 设置变量值
        Map<String, Integer> context = new HashMap<>();
        context.put("a", 5);
        context.put("b", 3);
        context.put("c", 2);
        
        // 解释执行
        int result = expression.interpret(context);
        System.out.println("(5 + 3) * 2 - 10 = " + result); // 输出: 6
    }
}

3.2 第二重:文法规则的定义

java 复制代码
// 更复杂的文法规则支持
public class BooleanExpression implements Expression {
    private Expression left;
    private Expression right;
    private String operator;
    
    public BooleanExpression(Expression left, Expression right, String operator) {
        this.left = left;
        this.right = right;
        this.operator = operator;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        int leftVal = left.interpret(context);
        int rightVal = right.interpret(context);
        
        switch (operator) {
            case ">": return leftVal > rightVal ? 1 : 0;
            case "<": return leftVal < rightVal ? 1 : 0;
            case ">=": return leftVal >= rightVal ? 1 : 0;
            case "<=": return leftVal <= rightVal ? 1 : 0;
            case "==": return leftVal == rightVal ? 1 : 0;
            case "!=": return leftVal != rightVal ? 1 : 0;
            default: throw new IllegalArgumentException("未知比较操作符: " + operator);
        }
    }
}

public class LogicalExpression implements Expression {
    private Expression left;
    private Expression right;
    private String operator;
    
    public LogicalExpression(Expression left, Expression right, String operator) {
        this.left = left;
        this.right = right;
        this.operator = operator;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        int leftVal = left.interpret(context);
        int rightVal = right.interpret(context);
        
        switch (operator) {
            case "AND": return (leftVal != 0 && rightVal != 0) ? 1 : 0;
            case "OR": return (leftVal != 0 || rightVal != 0) ? 1 : 0;
            default: throw new IllegalArgumentException("未知逻辑操作符: " + operator);
        }
    }
}

public class NotExpression implements Expression {
    private Expression expression;
    
    public NotExpression(Expression expression) {
        this.expression = expression;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        int value = expression.interpret(context);
        return value == 0 ? 1 : 0;
    }
}

3.3 第三重:解释器上下文

java 复制代码
// 增强的解释器上下文
public class InterpreterContext {
    private Map<String, Integer> variables = new HashMap<>();
    private Map<String, Function<Object[], Object>> functions = new HashMap<>();
    
    public InterpreterContext() {
        registerBuiltinFunctions();
    }
    
    public void setVariable(String name, int value) {
        variables.put(name, value);
    }
    
    public int getVariable(String name) {
        Integer value = variables.get(name);
        if (value == null) {
            throw new IllegalArgumentException("变量未定义: " + name);
        }
        return value;
    }
    
    public void registerFunction(String name, Function<Object[], Object> function) {
        functions.put(name, function);
    }
    
    public Object callFunction(String name, Object[] args) {
        Function<Object[], Object> function = functions.get(name);
        if (function == null) {
            throw new IllegalArgumentException("函数未定义: " + name);
        }
        return function.apply(args);
    }
    
    private void registerBuiltinFunctions() {
        // 注册内置函数
        registerFunction("max", args -> {
            if (args.length < 2) throw new IllegalArgumentException("max函数需要至少2个参数");
            return Math.max(((Number) args[0]).intValue(), ((Number) args[1]).intValue());
        });
        
        registerFunction("min", args -> {
            if (args.length < 2) throw new IllegalArgumentException("min函数需要至少2个参数");
            return Math.min(((Number) args[0]).intValue(), ((Number) args[1]).intValue());
        });
        
        registerFunction("sqrt", args -> {
            if (args.length != 1) throw new IllegalArgumentException("sqrt函数需要1个参数");
            return Math.sqrt(((Number) args[0]).doubleValue());
        });
    }
}

4. 实战案例:完整的规则引擎

java 复制代码
// 规则引擎 - 支持复杂的业务规则
public interface RuleExpression {
    boolean evaluate(RuleContext context);
    String getDescription();
}

// 规则上下文
@Data
public class RuleContext {
    private Map<String, Object> facts = new HashMap<>();
    
    public void setFact(String name, Object value) {
        facts.put(name, value);
    }
    
    public Object getFact(String name) {
        return facts.get(name);
    }
    
    @SuppressWarnings("unchecked")
    public <T> T getFact(String name, Class<T> type) {
        Object value = facts.get(name);
        return value != null ? (T) value : null;
    }
}

// 基础事实表达式
public class FactExpression implements RuleExpression {
    private String factName;
    private Object expectedValue;
    
    public FactExpression(String factName, Object expectedValue) {
        this.factName = factName;
        this.expectedValue = expectedValue;
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        Object actualValue = context.getFact(factName);
        return expectedValue.equals(actualValue);
    }
    
    @Override
    public String getDescription() {
        return factName + " = " + expectedValue;
    }
}

// 比较表达式
public class ComparisonExpression implements RuleExpression {
    private String factName;
    private Object value;
    private String operator;
    
    public ComparisonExpression(String factName, String operator, Object value) {
        this.factName = factName;
        this.operator = operator;
        this.value = value;
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        Object factValue = context.getFact(factName);
        
        if (factValue == null) {
            return false;
        }
        
        // 数值比较
        if (factValue instanceof Number && value instanceof Number) {
            double factDouble = ((Number) factValue).doubleValue();
            double valueDouble = ((Number) value).doubleValue();
            
            switch (operator) {
                case ">": return factDouble > valueDouble;
                case ">=": return factDouble >= valueDouble;
                case "<": return factDouble < valueDouble;
                case "<=": return factDouble <= valueDouble;
                case "==": return factDouble == valueDouble;
                case "!=": return factDouble != valueDouble;
            }
        }
        
        // 字符串比较
        if (factValue instanceof String && value instanceof String) {
            String factStr = (String) factValue;
            String valueStr = (String) value;
            
            switch (operator) {
                case "==": return factStr.equals(valueStr);
                case "!=": return !factStr.equals(valueStr);
                case "contains": return factStr.contains(valueStr);
                case "startsWith": return factStr.startsWith(valueStr);
                case "endsWith": return factStr.endsWith(valueStr);
            }
        }
        
        // 布尔比较
        if (factValue instanceof Boolean && value instanceof Boolean) {
            boolean factBool = (Boolean) factValue;
            boolean valueBool = (Boolean) value;
            
            switch (operator) {
                case "==": return factBool == valueBool;
                case "!=": return factBool != valueBool;
            }
        }
        
        throw new IllegalArgumentException("不支持的比较操作: " + factName + " " + operator + " " + value);
    }
    
    @Override
    public String getDescription() {
        return factName + " " + operator + " " + value;
    }
}

// 逻辑表达式
public class AndExpression implements RuleExpression {
    private List<RuleExpression> expressions;
    
    public AndExpression(RuleExpression... expressions) {
        this.expressions = Arrays.asList(expressions);
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        for (RuleExpression expression : expressions) {
            if (!expression.evaluate(context)) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public String getDescription() {
        return expressions.stream()
                .map(RuleExpression::getDescription)
                .collect(Collectors.joining(" AND ", "(", ")"));
    }
}

public class OrExpression implements RuleExpression {
    private List<RuleExpression> expressions;
    
    public OrExpression(RuleExpression... expressions) {
        this.expressions = Arrays.asList(expressions);
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        for (RuleExpression expression : expressions) {
            if (expression.evaluate(context)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    public String getDescription() {
        return expressions.stream()
                .map(RuleExpression::getDescription)
                .collect(Collectors.joining(" OR ", "(", ")"));
    }
}

public class NotExpression implements RuleExpression {
    private RuleExpression expression;
    
    public NotExpression(RuleExpression expression) {
        this.expression = expression;
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        return !expression.evaluate(context);
    }
    
    @Override
    public String getDescription() {
        return "NOT " + expression.getDescription();
    }
}

// 范围表达式
public class RangeExpression implements RuleExpression {
    private String factName;
    private Number min;
    private Number max;
    private boolean includeMin;
    private boolean includeMax;
    
    public RangeExpression(String factName, Number min, Number max) {
        this(factName, min, max, true, true);
    }
    
    public RangeExpression(String factName, Number min, Number max, boolean includeMin, boolean includeMax) {
        this.factName = factName;
        this.min = min;
        this.max = max;
        this.includeMin = includeMin;
        this.includeMax = includeMax;
    }
    
    @Override
    public boolean evaluate(RuleContext context) {
        Object factValue = context.getFact(factName);
        if (!(factValue instanceof Number)) {
            return false;
        }
        
        double value = ((Number) factValue).doubleValue();
        double minValue = min.doubleValue();
        double maxValue = max.doubleValue();
        
        boolean lowerBound = includeMin ? value >= minValue : value > minValue;
        boolean upperBound = includeMax ? value <= maxValue : value < maxValue;
        
        return lowerBound && upperBound;
    }
    
    @Override
    public String getDescription() {
        String lower = includeMin ? "[" : "(";
        String upper = includeMax ? "]" : ")";
        return factName + " ∈ " + lower + min + ", " + max + upper;
    }
}

// 规则引擎
public class RuleEngine {
    private List<Rule> rules = new ArrayList<>();
    
    public void addRule(Rule rule) {
        rules.add(rule);
    }
    
    public List<Rule> evaluate(RuleContext context) {
        return rules.stream()
                .filter(rule -> rule.evaluate(context))
                .collect(Collectors.toList());
    }
    
    public Rule findFirstMatch(RuleContext context) {
        return rules.stream()
                .filter(rule -> rule.evaluate(context))
                .findFirst()
                .orElse(null);
    }
}

// 规则
@Data
public class Rule {
    private String name;
    private int priority;
    private RuleExpression condition;
    private String action;
    
    public Rule(String name, int priority, RuleExpression condition, String action) {
        this.name = name;
        this.priority = priority;
        this.condition = condition;
        this.action = action;
    }
    
    public boolean evaluate(RuleContext context) {
        return condition.evaluate(context);
    }
    
    public String getDescription() {
        return name + ": IF " + condition.getDescription() + " THEN " + action;
    }
}

// 使用示例:贷款审批规则引擎
public class LoanApprovalEngine {
    public static void main(String[] args) {
        // 创建规则引擎
        RuleEngine engine = new RuleEngine();
        
        // 定义审批规则
        // 规则1:年龄必须 >= 18
        Rule ageRule = new Rule("年龄检查", 10, 
            new ComparisonExpression("age", ">=", 18), 
            "通过年龄检查");
        
        // 规则2:信用分数 >= 600
        Rule creditRule = new Rule("信用检查", 20, 
            new ComparisonExpression("creditScore", ">=", 600), 
            "通过信用检查");
        
        // 规则3:收入 >= 30000 或者 有担保人
        Rule incomeRule = new Rule("收入检查", 30,
            new OrExpression(
                new ComparisonExpression("income", ">=", 30000),
                new FactExpression("hasGuarantor", true)
            ),
            "通过收入检查");
        
        // 规则4:负债收入比 <= 0.5
        Rule debtRule = new Rule("负债检查", 40,
            new ComparisonExpression("debtToIncomeRatio", "<=", 0.5),
            "通过负债检查");
        
        // 规则5:综合审批规则
        Rule approvalRule = new Rule("贷款审批", 100,
            new AndExpression(ageRule.getCondition(), creditRule.getCondition(), 
                            incomeRule.getCondition(), debtRule.getCondition()),
            "批准贷款申请");
        
        // 规则6:拒绝规则 - 有不良信用记录
        Rule rejectionRule = new Rule("信用记录拒绝", 90,
            new FactExpression("hasBadCreditHistory", true),
            "拒绝贷款:不良信用记录");
        
        // 添加规则到引擎
        engine.addRule(ageRule);
        engine.addRule(creditRule);
        engine.addRule(incomeRule);
        engine.addRule(debtRule);
        engine.addRule(rejectionRule);
        engine.addRule(approvalRule);
        
        // 测试用例1:合格的申请人
        System.out.println("=== 测试用例1:合格的申请人 ===");
        RuleContext context1 = new RuleContext();
        context1.setFact("age", 25);
        context1.setFact("creditScore", 650);
        context1.setFact("income", 40000);
        context1.setFact("debtToIncomeRatio", 0.3);
        context1.setFact("hasGuarantor", false);
        context1.setFact("hasBadCreditHistory", false);
        
        Rule matchedRule = engine.findFirstMatch(context1);
        if (matchedRule != null) {
            System.out.println("匹配规则: " + matchedRule.getDescription());
        }
        
        // 测试用例2:有不良信用记录的申请人
        System.out.println("\n=== 测试用例2:有不良信用记录的申请人 ===");
        RuleContext context2 = new RuleContext();
        context2.setFact("age", 30);
        context2.setFact("creditScore", 700);
        context2.setFact("income", 50000);
        context2.setFact("debtToIncomeRatio", 0.2);
        context2.setFact("hasGuarantor", false);
        context2.setFact("hasBadCreditHistory", true);
        
        matchedRule = engine.findFirstMatch(context2);
        if (matchedRule != null) {
            System.out.println("匹配规则: " + matchedRule.getDescription());
        }
        
        // 显示所有匹配的规则
        System.out.println("\n=== 所有匹配的规则 ===");
        List<Rule> allMatches = engine.evaluate(context1);
        allMatches.forEach(rule -> 
            System.out.println(rule.getDescription()));
    }
}

5. Spring框架中的解释器模式

5.1 Spring EL(表达式语言)

java 复制代码
// 模拟Spring表达式语言解析
@Component
public class SpringExpressionParser {
    private final Map<String, Object> context = new HashMap<>();
    
    public void setVariable(String name, Object value) {
        context.put(name, value);
    }
    
    public Object evaluate(String expression) {
        // 简单的Spring EL解析实现
        return parseExpression(expression);
    }
    
    private Object parseExpression(String expr) {
        expr = expr.trim();
        
        // 处理字面量
        if (expr.matches("-?\\d+")) {
            return Integer.parseInt(expr);
        }
        if (expr.matches("-?\\d+\\.\\d+")) {
            return Double.parseDouble(expr);
        }
        if (expr.startsWith("'") && expr.endsWith("'")) {
            return expr.substring(1, expr.length() - 1);
        }
        if (expr.startsWith("\"") && expr.endsWith("\"")) {
            return expr.substring(1, expr.length() - 1);
        }
        if ("true".equalsIgnoreCase(expr) || "false".equalsIgnoreCase(expr)) {
            return Boolean.parseBoolean(expr);
        }
        
        // 处理变量
        if (context.containsKey(expr)) {
            return context.get(expr);
        }
        
        // 处理简单表达式
        if (expr.contains("+")) {
            String[] parts = expr.split("\\+");
            Object left = parseExpression(parts[0]);
            Object right = parseExpression(parts[1]);
            return add(left, right);
        }
        
        if (expr.contains("==")) {
            String[] parts = expr.split("==");
            Object left = parseExpression(parts[0]);
            Object right = parseExpression(parts[1]);
            return left.equals(right);
        }
        
        // 处理方法调用
        if (expr.contains(".")) {
            return parseMethodCall(expr);
        }
        
        throw new IllegalArgumentException("无法解析表达式: " + expr);
    }
    
    private Object add(Object left, Object right) {
        if (left instanceof Number && right instanceof Number) {
            if (left instanceof Integer && right instanceof Integer) {
                return (Integer) left + (Integer) right;
            }
            return ((Number) left).doubleValue() + ((Number) right).doubleValue();
        }
        if (left instanceof String || right instanceof String) {
            return left.toString() + right.toString();
        }
        throw new IllegalArgumentException("不支持的操作数类型: " + left.getClass() + " + " + right.getClass());
    }
    
    private Object parseMethodCall(String expr) {
        // 简单的方法调用解析
        String[] parts = expr.split("\\.");
        String objectName = parts[0];
        String methodPart = parts[1];
        
        Object target = context.get(objectName);
        if (target == null) {
            throw new IllegalArgumentException("对象未定义: " + objectName);
        }
        
        // 解析方法名和参数
        if (methodPart.contains("(") && methodPart.endsWith(")")) {
            String methodName = methodPart.substring(0, methodPart.indexOf("("));
            String argsStr = methodPart.substring(methodPart.indexOf("(") + 1, methodPart.length() - 1);
            
            // 简单参数解析
            Object[] args = Arrays.stream(argsStr.split(","))
                    .map(String::trim)
                    .map(this::parseExpression)
                    .toArray();
            
            return invokeMethod(target, methodName, args);
        }
        
        // 属性访问
        return getProperty(target, methodPart);
    }
    
    private Object invokeMethod(Object target, String methodName, Object[] args) {
        try {
            Class<?>[] paramTypes = Arrays.stream(args)
                    .map(Object::getClass)
                    .toArray(Class<?>[]::new);
            
            Method method = target.getClass().getMethod(methodName, paramTypes);
            return method.invoke(target, args);
        } catch (Exception e) {
            throw new RuntimeException("方法调用失败: " + methodName, e);
        }
    }
    
    private Object getProperty(Object target, String propertyName) {
        try {
            String getterName = "get" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
            Method getter = target.getClass().getMethod(getterName);
            return getter.invoke(target);
        } catch (Exception e) {
            throw new RuntimeException("属性访问失败: " + propertyName, e);
        }
    }
}

// 使用Spring EL的示例
@Component
public class BusinessRuleService {
    private final SpringExpressionParser expressionParser;
    
    @Autowired
    public BusinessRuleService(SpringExpressionParser expressionParser) {
        this.expressionParser = expressionParser;
    }
    
    public boolean evaluateBusinessRule(String ruleExpression, Map<String, Object> variables) {
        // 设置变量
        variables.forEach(expressionParser::setVariable);
        
        // 评估表达式
        Object result = expressionParser.evaluate(ruleExpression);
        
        if (result instanceof Boolean) {
            return (Boolean) result;
        }
        
        throw new IllegalArgumentException("规则表达式必须返回布尔值: " + ruleExpression);
    }
}

5.2 Spring Security的表达权限控制

java 复制代码
// 模拟Spring Security的权限表达式
@Component
public class SecurityExpressionParser {
    
    public boolean evaluate(String expression, SecurityContext context) {
        return parseSecurityExpression(expression, context);
    }
    
    private boolean parseSecurityExpression(String expr, SecurityContext context) {
        expr = expr.trim();
        
        // 处理hasRole表达式
        if (expr.startsWith("hasRole(") && expr.endsWith(")")) {
            String role = expr.substring(8, expr.length() - 1).replace("'", "");
            return context.hasRole(role);
        }
        
        // 处理hasAnyRole表达式
        if (expr.startsWith("hasAnyRole(") && expr.endsWith(")")) {
            String rolesStr = expr.substring(11, expr.length() - 1).replace("'", "");
            String[] roles = rolesStr.split(",");
            return Arrays.stream(roles)
                    .anyMatch(context::hasRole);
        }
        
        // 处理hasAuthority表达式
        if (expr.startsWith("hasAuthority(") && expr.endsWith(")")) {
            String authority = expr.substring(13, expr.length() - 1).replace("'", "");
            return context.hasAuthority(authority);
        }
        
        // 处理permitAll表达式
        if ("permitAll".equals(expr)) {
            return true;
        }
        
        // 处理denyAll表达式
        if ("denyAll".equals(expr)) {
            return false;
        }
        
        // 处理逻辑表达式
        if (expr.contains(" and ")) {
            String[] parts = expr.split(" and ");
            return Arrays.stream(parts)
                    .allMatch(part -> parseSecurityExpression(part, context));
        }
        
        if (expr.contains(" or ")) {
            String[] parts = expr.split(" or ");
            return Arrays.stream(parts)
                    .anyMatch(part -> parseSecurityExpression(part, context));
        }
        
        throw new IllegalArgumentException("未知的安全表达式: " + expr);
    }
}

// 安全上下文
@Data
public class SecurityContext {
    private UserPrincipal user;
    private String requestUri;
    private String method;
    
    public boolean hasRole(String role) {
        return user != null && user.getRoles().contains(role);
    }
    
    public boolean hasAuthority(String authority) {
        return user != null && user.getAuthorities().contains(authority);
    }
}

// 用户主体
@Data
public class UserPrincipal {
    private String username;
    private Set<String> roles = new HashSet<>();
    private Set<String> authorities = new HashSet<>();
    
    public UserPrincipal(String username, String... roles) {
        this.username = username;
        this.roles.addAll(Arrays.asList(roles));
    }
}

// 使用方法注解进行权限控制
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface PreAuthorize {
    String value();
}

// 安全拦截器
@Component
public class SecurityInterceptor {
    private final SecurityExpressionParser expressionParser;
    
    @Autowired
    public SecurityInterceptor(SecurityExpressionParser expressionParser) {
        this.expressionParser = expressionParser;
    }
    
    public boolean checkPermission(String expression, SecurityContext context) {
        return expressionParser.evaluate(expression, context);
    }
}

6. 解释器模式的进阶用法

6.1 语法树可视化

java 复制代码
// 支持可视化的表达式接口
public interface VisualExpression extends Expression {
    String toTreeString();
    String toTreeString(int indent);
}

// 可可视化的数学表达式
public class VisualAddExpression extends AddExpression implements VisualExpression {
    public VisualAddExpression(Expression left, Expression right) {
        super(left, right);
    }
    
    @Override
    public String toTreeString() {
        return toTreeString(0);
    }
    
    @Override
    public String toTreeString(int indent) {
        String indentStr = "  ".repeat(indent);
        StringBuilder sb = new StringBuilder();
        sb.append(indentStr).append("AddExpression\n");
        
        if (left instanceof VisualExpression) {
            sb.append(((VisualExpression) left).toTreeString(indent + 1));
        } else {
            sb.append(indentStr).append("  ").append(left).append("\n");
        }
        
        if (right instanceof VisualExpression) {
            sb.append(((VisualExpression) right).toTreeString(indent + 1));
        } else {
            sb.append(indentStr).append("  ").append(right).append("\n");
        }
        
        return sb.toString();
    }
}

// 语法树可视化工具
public class ExpressionTreeVisualizer {
    public static void visualize(Expression expression) {
        if (expression instanceof VisualExpression) {
            System.out.println("表达式语法树:");
            System.out.println(((VisualExpression) expression).toTreeString());
        } else {
            System.out.println("表达式: " + expression);
        }
    }
    
    public static String generateGraphviz(Expression expression) {
        StringBuilder sb = new StringBuilder();
        sb.append("digraph ExpressionTree {\n");
        sb.append("  node [shape=box];\n");
        generateGraphvizNodes(expression, sb, "root");
        sb.append("}\n");
        return sb.toString();
    }
    
    private static void generateGraphvizNodes(Expression expr, StringBuilder sb, String parentId) {
        String nodeId = parentId + "_" + System.identityHashCode(expr);
        String label = expr.getClass().getSimpleName();
        
        if (expr instanceof NumberExpression) {
            label = ((NumberExpression) expr).interpret(null) + "";
        } else if (expr instanceof VariableExpression) {
            label = ((VariableExpression) expr).interpret(null) + "";
        }
        
        sb.append("  ").append(nodeId).append(" [label=\"").append(label).append("\"];\n");
        sb.append("  ").append(parentId).append(" -> ").append(nodeId).append(";\n");
        
        // 递归处理子节点
        // 这里需要根据具体表达式类型访问其子节点
    }
}

6.2 解释器性能优化

java 复制代码
// 带缓存的解释器
public class CachingExpression implements Expression {
    private final Expression expression;
    private final Map<Map<String, Integer>, Integer> cache = new ConcurrentHashMap<>();
    
    public CachingExpression(Expression expression) {
        this.expression = expression;
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        return cache.computeIfAbsent(new HashMap<>(context), k -> expression.interpret(context));
    }
}

// 预编译的解释器
public class CompiledExpression implements Expression {
    private final Expression expression;
    private final Map<String, Integer> fixedContext;
    private Integer cachedResult;
    
    public CompiledExpression(Expression expression, Map<String, Integer> fixedContext) {
        this.expression = expression;
        this.fixedContext = new HashMap<>(fixedContext);
    }
    
    @Override
    public int interpret(Map<String, Integer> context) {
        // 如果上下文与预编译时相同,使用缓存结果
        if (cachedResult != null && fixedContext.equals(context)) {
            return cachedResult;
        }
        
        // 否则重新计算并缓存
        cachedResult = expression.interpret(context);
        return cachedResult;
    }
    
    public void precompute() {
        cachedResult = expression.interpret(fixedContext);
    }
}

// 解释器工厂
public class ExpressionFactory {
    private static final Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
    
    public static Expression getExpression(String expressionStr) {
        return expressionCache.computeIfAbsent(expressionStr, k -> {
            System.out.println("编译表达式: " + expressionStr);
            return ExpressionBuilder.build(expressionStr);
        });
    }
    
    public static Expression getCachedExpression(String expressionStr) {
        Expression baseExpression = getExpression(expressionStr);
        return new CachingExpression(baseExpression);
    }
}

7. 解释器模式 vs 其他模式

7.1 解释器模式 vs 访问者模式

  • 解释器模式:为语言创建解释器,关注语法的表示和解释
  • 访问者模式:在不变更各元素类的前提下定义作用于这些元素的新操作

7.2 解释器模式 vs 组合模式

  • 解释器模式:专门用于语言解释,有明确的文法规则
  • 组合模式:处理部分-整体层次结构,不关注具体语义

7.3 解释器模式 vs 策略模式

  • 解释器模式:处理语言文法,构建抽象语法树
  • 策略模式:封装算法,在运行时选择不同的算法实现

8. 总结与思考

8.1 解释器模式的优点

  1. 易于扩展文法:新增语法规则只需要新增表达式类
  2. 易于实现语法:每个语法规则都可以表示为一个类
  3. 易于改变和扩展语言:通过继承来改变或扩展语言的文法
  4. 实现文法简单:文法由很多类表示,易于实现

8.2 解释器模式的缺点

  1. 执行效率较低:解释器模式通常使用递归或循环调用,性能较低
  2. 对于复杂文法难以维护:文法规则过多时,类数量会急剧增加
  3. 应用场景有限:只有在特定领域需要语言解释时才适用
  4. 难以处理复杂的语法分析:需要配合其他模式如解析器模式

8.3 设计思考

解释器模式的本质是**"语言解释的抽象语法树"**。它通过将语言的文法规则表示为类的层次结构,并构建抽象语法树来解释语言中的句子。

深入思考的角度

"解释器模式的核心价值在于它为特定领域语言(DSL)提供了一种优雅的实现方式。通过将文法规则对象化,我们可以构建灵活且可扩展的语言处理系统。"

在实际应用中,解释器模式有很多优秀的实践:

  • 正则表达式引擎
  • SQL查询解释器
  • 业务规则引擎
  • 数学表达式计算器
  • 模板引擎

从系统设计的角度看,解释器模式特别适合以下场景:

  • 当有一个语言需要解释执行,并且可将该语言中的句子表示为一个抽象语法树时
  • 文法比较简单,对于复杂的文法,文法的类层次变得庞大而无法管理
  • 效率不是关键问题,因为解释器模式通常效率不高

最佳实践建议

  1. 仔细设计文法规则,确保文法足够简单
  2. 考虑使用解析器生成工具(如ANTLR)来处理复杂文法
  3. 为解释器添加缓存机制提高性能
  4. 考虑使用访问者模式来遍历抽象语法树
  5. 为表达式提供良好的调试和可视化支持

使用场景判断

  • 适合:领域特定语言、简单文法、规则引擎、查询语言
  • 不适合:复杂文法、高性能要求、通用编程语言

下一篇预告:设计模式手册015 - 迭代器模式:如何提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示?


版权声明:本文为CSDN博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

相关推荐
ZHE|张恒39 分钟前
设计模式(十六)迭代器模式 — 统一访问集合元素的方式,不暴露内部结构
设计模式·迭代器模式
lichong9511 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
xu_yule1 小时前
Linux_14(多线程)线程控制+C++多线程
java·开发语言·jvm
合作小小程序员小小店1 小时前
网页开发,在线%新版本旅游管理%系统,基于eclipse,html,css,jquery,servlet,jsp,mysql数据库
java·数据库·eclipse·html·intellij-idea·旅游·jsp
组合缺一2 小时前
Spring Boot 国产化替代方案。Solon v3.7.2, v3.6.5, v3.5.9 发布(支持 LTS)
java·后端·spring·ai·web·solon·mcp
s***11702 小时前
常见的 Spring 项目目录结构
java·后端·spring
O***P5712 小时前
记录 idea 启动 tomcat 控制台输出乱码问题解决
java·tomcat·intellij-idea
7***47712 小时前
在2023idea中如何创建SpringBoot
java·spring boot·后端