当前位置: 首页 > news >正文

对解释器模式的理解

对解释器模式的理解

    • 一、场景
      • 1、题目【[来源](https://kamacoder.com/problempage.php?pid=1096)】
        • 1.1 题目描述
        • 1.2 输入描述
        • 1.3 输出描述
        • 1.4 输入示例
        • 1.5 输出示例
    • 二、不采用解释器模式
      • 1、代码
      • 2、“缺点”
    • 三、采用解释器模式
      • 1、代码
      • 2、“优点”
    • 四、思考
      • 1、解释器模式的意义

一、场景

1、题目【来源】

1.1 题目描述

小明正在设计一个计算器,用于解释用户输入的简单数学表达式,每个表达式都是由整数、加法操作符+、乘法操作符组成的,表达式中的元素之间用空格分隔,请你使用解释器模式帮他实现这个系统。

1.2 输入描述

每行包含一个数学表达式,表达式中包含整数、加法操作符(+)和乘法操作符(*)。 表达式中的元素之间用空格分隔。

1.3 输出描述

对于每个输入的数学表达式,每行输出一个整数,表示对应表达式的计算结果。

1.4 输入示例
2 + 3
5 * 2
3 + 4 * 2
1.5 输出示例
5
10
11

二、不采用解释器模式

1、代码

  • 计算器
public class Calculator {
    private final Deque<Integer> numberStack;
    private final Deque<String> operatorStack;

    public Calculator() {
        numberStack = new ArrayDeque<>();
        operatorStack = new ArrayDeque<>();
    }

    public Integer calculate(String expression) {
        if (expression == null || expression.isEmpty()) {
            return null;
        }


        String[] tokens = expression.trim().split("\\s+");
        for (String token : tokens) {
            if (isOperator(token)) {
                while (!operatorStack.isEmpty() && ("*".equals(operatorStack.peek()) && "+".equals(token))) {
                    numberStack.push(numberStack.pop() * numberStack.pop());
                }

                operatorStack.push(token);

            } else {
                numberStack.push(Integer.parseInt(token));
            }
        }

        while (!operatorStack.isEmpty()) {
            Integer num2 = numberStack.pop();
            Integer num1 = numberStack.pop();
            String operator = operatorStack.pop();

            if ("+".equals(operator)) {
                numberStack.push(num1 + num2);
            } else if ("*".equals(operator)) {
                numberStack.push(num1 * num2);
            }
        }


        return numberStack.pop();
    }

    private static boolean isOperator(String s) {
        return "+".equals(s) || "*".equals(s);
    }
}
  • 客户端
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        Calculator calculator = new Calculator();

        while (scanner.hasNextLine()) {
            String expression = scanner.nextLine();
            System.out.println(calculator.calculate(expression));
        }
    }
}

2、“缺点”

  • 倒反天罡了,我觉得不采用解释器模式反而更好。😃

三、采用解释器模式

1、代码

  • 定义表达式
public interface Expression {
    int interpret();
}

public class NumberExpression implements Expression {
    private final int number;

    public NumberExpression(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return number;
    }
}

public class AddExpression implements Expression {
    private final Expression left;
    private final Expression right;

    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

public class MultiplyExpression implements Expression {
    private final Expression left;
    private final Expression right;

    public MultiplyExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}
  • 计算器
public class Calculator {
    private final Deque<Expression> expressionStack = new ArrayDeque<>();
    private final Deque<String> operatorStack = new ArrayDeque<>();

    public Integer calculate(String expression) {
        if (expression == null || expression.isEmpty()) {
            return null;
        }

        String[] tokens = expression.trim().split("\\s+");
        for (String token : tokens) {
            if (isOperator(token)) {
                // 处理操作符优先级
                while (!operatorStack.isEmpty() && ("*".equals(operatorStack.peek()) && "+".equals(token))) {
                    processOperator();
                }
                operatorStack.push(token);
            } else {
                expressionStack.push(new NumberExpression(Integer.parseInt(token)));
            }
        }

        // 处理剩余的操作符
        while (!operatorStack.isEmpty()) {
            processOperator();
        }

        // 最终栈中只剩下一个表达式对象
        return expressionStack.pop().interpret();
    }

    private void processOperator() {
        Expression right = expressionStack.pop();
        Expression left = expressionStack.pop();
        String operator = operatorStack.pop();

        Expression operation;
        if ("+".equals(operator)) {
            operation = new AddExpression(left, right);
        } else if ("*".equals(operator)) {
            operation = new MultiplyExpression(left, right);
        } else {
            throw new IllegalArgumentException("Unknown operator: " + operator);
        }

        expressionStack.push(operation);
    }

    private static boolean isOperator(String s) {
        return "+".equals(s) || "*".equals(s);
    }
}
  • 客户端代码和之前一样

2、“优点”

  • 有种画蛇添足的感觉,貌似没有体现解释器模式的优势。

四、思考

1、解释器模式的意义

  • 抽丝剥茧,从一段简单的代码说起:

public class InterpretTest {
    public static void main(String[] args) {
        // 3 + 4 * 2
        Expression expression = new AddExpression(new NumberExpression(3),
                new MultiplyExpression(new NumberExpression(4), new NumberExpression(2)));

        System.out.println(expression.interpret());
    }
}
  • 当用户输入字符串“3 + 4 * 2”的时候,转换成Expression本身就比较复杂,但一旦转换好了,如上所示,Expression就发挥优势了。

  • 因此,当我们需要解释语法规则时,应该是分为2步的:

    • (1)将字符串类型的表达式,转成Expression对象。
    • (2)Expression对象解释执行。【这一步才体现了解释模式的价值】

    如果不采用解释模式,实际上如同“二、不采用解释器模式”的代码所示,是一边解析表达式字符串,一边执行的。

  • 如果解释执行本身就比较简单(计算器的例子便是如此),先转成Expression对象再解释执行的意义确实不大。

  • 但如果解释执行本身就比较复杂,而且如何解释执行可能变化,这时候解释器模式的价值就体现出来了。

    目前没在实战中遇到过,等遇到了感受就深了。

相关文章:

  • 互联网三高架构设计
  • JAVA对象创建过程和类加载过程
  • 整车CAN网络和CANoe
  • 如何使用Python自动化测试工具Selenium进行网页自动化?
  • Java类加载机制深度解析
  • 蓝桥杯基础算法-字符串与集合
  • 瑞萨RA4M2使用心得-KEIL5的第一次编译
  • pipwire cpu 100%使用率的问题
  • 大模型学习五:‌DeepSeek Janus-Pro-7B 多模态半精度本地部署指南:环境是腾讯cloudstudio高性能GPU 16G免费算力
  • 定制一款国密浏览器(3):修改浏览器应用程序安装路径
  • Java 基础-31-枚举-认识枚举
  • 每日一题(小白)回溯篇4
  • ngx_timezone_update
  • Python----计算机视觉处理(Opencv:道路检测之车道线拟合)
  • OpenSceneGraph 中的 osg::Transform详解
  • 图片尺寸修改软件下载
  • 车载ECU底软测试:方法与技术的深度解析
  • 利用NumPy核心知识点优化TensorFlow模型训练过程
  • 大厂机考——各算法与数据结构详解
  • ERP系统五大生产模式概述
  • 注册公司网站源码/百度搜首页
  • 专门做鞋子的网站吗/seo文章
  • 免费注册网站怎么做链接/百度人工服务热线电话
  • 前段网站开发社会实践报告/上海优化网站公司哪家好
  • 哪个网站专门做母婴/网址大全名称
  • flash网站开发用什么语言/怎么样推广自己的店铺和产品