Deepeek用大白话讲解 → 解释器模式(企业级场景1,规则引擎2,表达式解析3,SQL解析4)

解释器模式大白话讲解

一句话概括

就像翻译官:你把一种语言(表达式)交给它,它帮你翻译成你能理解的意思(结果)


现实生活比喻

场景1:计算器

  • :输入 "1 + 2 * 3"
  • 解释器 :分析这个字符串,理解*+优先级高,先算2*3=6,再算1+6=7
  • 结果7

场景2:SQL查询

  • :输入 "SELECT * FROM users WHERE age > 18"
  • 解释器 :分析语法,找出users表中所有age大于18的记录
  • 结果:符合条件的数据列表

完整代码示例

场景1:四则运算计算器

java 复制代码
/**
 * 解释器模式 - 四则运算计算器
 */
public class Main {
    public static void main(String[] args) {
        System.out.println("=== 四则运算计算器 ===");
        
        // 测试简单表达式
        String expression1 = "3 + 5";
        String expression2 = "10 - 4";
        String expression3 = "6 * 2";
        String expression4 = "15 / 3";
        
        Calculator calculator = new Calculator();
        
        System.out.println(expression1 + " = " + calculator.calculate(expression1));
        System.out.println(expression2 + " = " + calculator.calculate(expression2));
        System.out.println(expression3 + " = " + calculator.calculate(expression3));
        System.out.println(expression4 + " = " + calculator.calculate(expression4));
        
        // 测试复杂表达式
        System.out.println("\n=== 复杂表达式测试 ===");
        String expression5 = "3 + 5 * 2 - 8 / 4";
        System.out.println(expression5 + " = " + calculator.calculate(expression5));
        
        // 测试带括号的表达式
        System.out.println("\n=== 带括号表达式测试 ===");
        String expression6 = "(3 + 5) * 2";
        System.out.println(expression6 + " = " + calculator.calculate(expression6));
        
        String expression7 = "3 * (5 + 2) - 4";
        System.out.println(expression7 + " = " + calculator.calculate(expression7));
        
        // 测试错误表达式
        System.out.println("\n=== 错误表达式测试 ===");
        String errorExpression = "3 + * 5";
        try {
            System.out.println(errorExpression + " = " + calculator.calculate(errorExpression));
        } catch (IllegalArgumentException e) {
            System.out.println("表达式错误: " + e.getMessage());
        }
    }
}

/**
 * 抽象表达式接口
 */
interface Expression {
    int interpret();
}

/**
 * 终结符表达式 - 数字
 */
class NumberExpression implements Expression {
    private int number;
    
    public NumberExpression(int number) {
        this.number = number;
    }
    
    @Override
    public int interpret() {
        return number;
    }
}

/**
 * 非终结符表达式 - 加法
 */
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("除数不能为0");
        }
        return left.interpret() / divisor;
    }
}

/**
 * 计算器 - 上下文
 */
class Calculator {
    /**
     * 解析并计算表达式
     */
    public int calculate(String expression) {
        // 移除空格
        expression = expression.replaceAll("\\s+", "");
        
        // 使用栈来处理表达式
        Stack<Expression> numberStack = new Stack<>();
        Stack<Character> operatorStack = new Stack<>();
        
        for (int i = 0; i < expression.length(); i++) {
            char ch = expression.charAt(i);
            
            if (Character.isDigit(ch)) {
                // 处理多位数字
                int num = 0;
                while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
                    num = num * 10 + (expression.charAt(i) - '0');
                    i++;
                }
                i--; // 回退一位
                numberStack.push(new NumberExpression(num));
            } else if (ch == '(') {
                operatorStack.push(ch);
            } else if (ch == ')') {
                // 处理括号内的所有运算
                while (!operatorStack.isEmpty() && operatorStack.peek() != '(') {
                    processOperation(numberStack, operatorStack);
                }
                operatorStack.pop(); // 弹出 '('
            } else if (isOperator(ch)) {
                // 处理运算符优先级
                while (!operatorStack.isEmpty() && precedence(operatorStack.peek()) >= precedence(ch)) {
                    processOperation(numberStack, operatorStack);
                }
                operatorStack.push(ch);
            } else {
                throw new IllegalArgumentException("非法字符: " + ch);
            }
        }
        
        // 处理剩余的运算符
        while (!operatorStack.isEmpty()) {
            processOperation(numberStack, operatorStack);
        }
        
        return numberStack.pop().interpret();
    }
    
    /**
     * 处理一次运算
     */
    private void processOperation(Stack<Expression> numberStack, Stack<Character> operatorStack) {
        char operator = operatorStack.pop();
        Expression right = numberStack.pop();
        Expression left = numberStack.pop();
        
        switch (operator) {
            case '+':
                numberStack.push(new AddExpression(left, right));
                break;
            case '-':
                numberStack.push(new SubtractExpression(left, right));
                break;
            case '*':
                numberStack.push(new MultiplyExpression(left, right));
                break;
            case '/':
                numberStack.push(new DivideExpression(left, right));
                break;
        }
    }
    
    /**
     * 判断是否是运算符
     */
    private boolean isOperator(char ch) {
        return ch == '+' || ch == '-' || ch == '*' || ch == '/';
    }
    
    /**
     * 获取运算符优先级
     */
    private int precedence(char operator) {
        switch (operator) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            default:
                return 0;
        }
    }
}

运行结果

复制代码
=== 四则运算计算器 ===
3 + 5 = 8
10 - 4 = 6
6 * 2 = 12
15 / 3 = 5

=== 复杂表达式测试 ===
3 + 5 * 2 - 8 / 4 = 11

=== 带括号表达式测试 ===
(3 + 5) * 2 = 16
3 * (5 + 2) - 4 = 17

=== 错误表达式测试 ===
表达式错误: 非法字符: *

场景2:布尔表达式解析器

java 复制代码
/**
 * 解释器模式 - 布尔表达式解析器
 */
public class BooleanExpressionExample {
    public static void main(String[] args) {
        System.out.println("=== 布尔表达式解析器 ===");
        
        // 创建上下文(变量值)
        Context context = new Context();
        context.setVariable("A", true);
        context.setVariable("B", false);
        context.setVariable("C", true);
        context.setVariable("D", false);
        
        // 解析表达式
        System.out.println("\n--- 测试简单表达式 ---");
        testExpression("A AND B", context);      // true AND false = false
        testExpression("A OR B", context);       // true OR false = true
        testExpression("NOT A", context);        // NOT true = false
        
        System.out.println("\n--- 测试复杂表达式 ---");
        testExpression("A AND B OR C", context);  // true AND false OR true = true
        testExpression("(A OR B) AND C", context); // (true OR false) AND true = true
        testExpression("NOT (A AND B)", context);  // NOT (true AND false) = true
        
        System.out.println("\n--- 测试不同变量值 ---");
        context.setVariable("A", false);
        context.setVariable("B", true);
        testExpression("A AND B", context);      // false AND true = false
        testExpression("A OR B", context);       // false OR true = true
    }
    
    private static void testExpression(String expression, Context context) {
        try {
            BooleanExpression boolExpr = new BooleanExpressionParser(expression).parse();
            boolean result = boolExpr.interpret(context);
            System.out.println(expression + " = " + result);
        } catch (Exception e) {
            System.out.println("解析错误: " + e.getMessage());
        }
    }
}

/**
 * 上下文 - 存储变量值
 */
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;
    }
}

/**
 * 抽象布尔表达式接口
 */
interface BooleanExpression {
    boolean interpret(Context context);
}

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

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

/**
 * 非终结符表达式 - AND运算
 */
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);
    }
}

/**
 * 非终结符表达式 - OR运算
 */
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);
    }
}

/**
 * 非终结符表达式 - NOT运算
 */
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 String expression;
    private int pos = 0;
    
    public BooleanExpressionParser(String expression) {
        this.expression = expression.replaceAll("\\s+", "");
    }
    
    public BooleanExpression parse() {
        return parseOrExpression();
    }
    
    // 解析OR表达式: A OR B OR C
    private BooleanExpression parseOrExpression() {
        BooleanExpression left = parseAndExpression();
        
        while (pos < expression.length() && peek().equals("OR")) {
            consume("OR");
            BooleanExpression right = parseAndExpression();
            left = new OrExpression(left, right);
        }
        
        return left;
    }
    
    // 解析AND表达式: A AND B AND C
    private BooleanExpression parseAndExpression() {
        BooleanExpression left = parseNotExpression();
        
        while (pos < expression.length() && peek().equals("AND")) {
            consume("AND");
            BooleanExpression right = parseNotExpression();
            left = new AndExpression(left, right);
        }
        
        return left;
    }
    
    // 解析NOT表达式: NOT A
    private BooleanExpression parseNotExpression() {
        if (peek().equals("NOT")) {
            consume("NOT");
            return new NotExpression(parseNotExpression());
        }
        return parsePrimary();
    }
    
    // 解析基本表达式: 变量、常量或括号表达式
    private BooleanExpression parsePrimary() {
        String token = peek();
        
        if (token.equals("(")) {
            consume("(");
            BooleanExpression expr = parseOrExpression();
            consume(")");
            return expr;
        } else if (token.equals("TRUE")) {
            consume("TRUE");
            return new ConstantExpression(true);
        } else if (token.equals("FALSE")) {
            consume("FALSE");
            return new ConstantExpression(false);
        } else {
            // 变量
            if (!isValidVariable(token)) {
                throw new IllegalArgumentException("非法变量名: " + token);
            }
            consume(token);
            return new VariableExpression(token);
        }
    }
    
    // 查看下一个token
    private String peek() {
        if (pos >= expression.length()) {
            return "";
        }
        
        // 如果是运算符或括号
        if (expression.charAt(pos) == '(' || expression.charAt(pos) == ')') {
            return String.valueOf(expression.charAt(pos));
        }
        
        // 提取单词
        int start = pos;
        while (pos < expression.length() && Character.isLetter(expression.charAt(pos))) {
            pos++;
        }
        String word = expression.substring(start, pos);
        pos = start; // 重置位置
        
        // 检查是否是关键字
        if (word.equalsIgnoreCase("AND") || word.equalsIgnoreCase("OR") || 
            word.equalsIgnoreCase("NOT") || word.equalsIgnoreCase("TRUE") || 
            word.equalsIgnoreCase("FALSE")) {
            return word.toUpperCase();
        }
        
        return word;
    }
    
    // 消费一个token
    private void consume(String expected) {
        String token = peek();
        if (!token.equals(expected)) {
            throw new IllegalArgumentException("期望: " + expected + ", 实际: " + token);
        }
        
        if (token.length() == 1 && (token.equals("(") || token.equals(")"))) {
            pos++; // 括号
        } else {
            pos += token.length(); // 单词
        }
    }
    
    // 检查是否是有效的变量名
    private boolean isValidVariable(String token) {
        return token.matches("[A-Za-z][A-Za-z0-9_]*");
    }
}

运行结果

复制代码
=== 布尔表达式解析器 ===

--- 测试简单表达式 ---
A AND B = false
A OR B = true
NOT A = false

--- 测试复杂表达式 ---
A AND B OR C = true
(A OR B) AND C = true
NOT (A AND B) = true

--- 测试不同变量值 ---
A AND B = false
A OR B = true

解释器模式的核心结构

复制代码
      Client(客户端)
         ↓ 输入表达式
      Context(上下文)
         ↓
  AbstractExpression(抽象表达式)
         ↑ 实现
TerminalExpression(终结符表达式)
NonterminalExpression(非终结符表达式)

关键概念:

  • 抽象语法树(AST):表达式解析后的树形结构
  • 终结符:不能再分解的基本元素(数字、变量)
  • 非终结符:由其他表达式组成的复合元素(运算符、函数)
  • 上下文:存储解释器需要的外部信息

解释器模式的工作流程

复制代码
输入表达式 → 词法分析 → 语法分析 → 构建AST → 解释执行 → 输出结果
    ↓          ↓          ↓          ↓          ↓         ↓
  "1+2*3" → ["1","+","2","*","3"] → 语法树 → 遍历计算 → 7

适用场景(大白话版)

适合用解释器模式的场景:

  1. 简单语言解释器

    java 复制代码
    // 正则表达式、SQL查询、四则运算
    // 需要定义简单语法规则的系统
  2. 配置文件解析

    java 复制代码
    // Spring的SpEL表达式、日志配置表达式
    // 需要动态解析配置的系统
  3. 业务规则引擎

    java 复制代码
    // 风控规则、促销规则、审批规则
    // 规则经常变化,需要灵活配置
  4. 模板引擎

    java 复制代码
    // JSP、Thymeleaf、Freemarker
    // 需要解释模板语法的系统

不适合的场景:

  1. 复杂语法:如果语法非常复杂,解释器模式会变得很臃肿
  2. 性能要求高:解释执行通常比编译执行慢
  3. 语法经常变化:每次语法变化都需要修改解释器
  4. 已经有现成解析器:如JSON、XML解析有成熟库

优缺点

优点:

  • 易于扩展语法:新增语法规则只需新增表达式类
  • 易于实现:每个语法规则对应一个类,结构清晰
  • 灵活性高:可以动态改变解释逻辑

缺点:

  • 复杂语法难维护:语法复杂时,类数量会爆炸
  • 效率较低:解释执行比直接执行慢
  • 难以调试:解释器错误难以定位

实际应用案例

1. Java正则表达式

java 复制代码
// Pattern就是解释器模式的实现
Pattern pattern = Pattern.compile("a*b");
Matcher matcher = pattern.matcher("aaaaab");
boolean matches = matcher.matches(); // true

2. Spring表达式语言(SpEL)

java 复制代码
// SpEL使用解释器模式解析表达式
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello ' + name");
String message = exp.getValue(context, String.class);

3. SQL解析器

java 复制代码
// 数据库查询优化器使用解释器模式
// 解析SQL语句,生成执行计划
SELECT * FROM users WHERE age > 18 AND status = 'ACTIVE'

4. 规则引擎(Drools)

java 复制代码
// 规则引擎使用解释器模式解析业务规则
rule "成年人规则"
when
    $p : Person(age > 18)
then
    $p.setAdult(true);
end

与编译器的区别

方面 解释器模式 编译器
执行方式 边解析边执行 先编译后执行
速度 较慢 较快
灵活性 高,可动态修改 低,需要重新编译
典型应用 脚本语言、配置文件 系统编程语言

总结

解释器模式就是:

  • 语言翻译官:把一种语言翻译成另一种语言
  • 规则执行者:按照预定义规则执行操作
  • 公式计算器:解析并计算公式

核心口诀:

特定语言要解析,

解释模式来解决。

语法规则拆细碎,

逐条解释出结果!

就像现实中的:

  • 📖 翻译软件:把英文翻译成中文
  • 🧮 计算器:把数学表达式算出结果
  • 🗺️ 地图应用:把地址解析成坐标
  • 📧 邮件过滤器:把过滤规则应用到邮件

记住:当需要解释特定语法或规则,且语法相对简单固定时,考虑使用解释器模式!对于复杂语法,考虑使用专门的解析器生成工具(如ANTLR、Yacc等)。

相关推荐
后端小张8 小时前
【JAVA 进阶】深入拆解SpringBoot自动配置:从原理到实战的完整指南
java·开发语言·spring boot·后端·spring·spring cloud·springboot
一起养小猫8 小时前
《Java数据结构与算法》第四篇(二)二叉树的性质、定义与链式存储实现
java·数据结构·算法
你不是我我8 小时前
【Java 开发日记】我们来说一下消息的可靠性投递
java·开发语言
风月歌8 小时前
小程序项目之“健康早知道”微信小程序源码(java+小程序+mysql)
java·微信小程序·小程序·毕业设计·源码
czlczl2002092510 小时前
告别 try-catch 地狱:Spring Boot 全局异常处理 (GlobalExceptionHandler) 最佳实践
java·spring boot·后端
Goldn.16 小时前
Java核心技术栈全景解析:从Web开发到AI融合
java· spring boot· 微服务· ai· jvm· maven· hibernate
饕餮争锋16 小时前
SQL条件中WHERE 1=1 的功能
数据库·sql
李慕婉学姐17 小时前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
m0_7400437317 小时前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j