首页 > 其他分享 >设计模式-解释器模式

设计模式-解释器模式

时间:2024-06-22 23:42:58浏览次数:20  
标签:解释器 right calculate 模式 new 设计模式 public interpret IArithmeticInterpreter

解释器模式(InterPreter Pattern)

解释器模式是指给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用 该表示 来解释语言中的句子,并按照规定的语法进行解析的模式,属于行为型模式。

比如编译器可以将源码编译为机器码,让CPU能进行识别并运行。解释器模式的作用其实与编译器一样,都是对固定的文法进行解释,构建出一个解释句子的解释器。

解释器模式实际开发中使用较少,一般源码中会使用,比如Spring的el表达式,以及jdk对正则的支持等

适用场景

  • 一些重复出现的问题可以用一种简单的语言来进行表达
  • 一个简单语法需要解释的场景

角色

  • 抽象表达式Expression:负责定义一个解释方法interpret,交由具体子类进行具体解释
  • 终结符表达式TerminalExpression:实现文法中与终结符有关的操作。文法中的每一个终结符都有一个具体终结表达式与之相呼应。比如R=R1+R2,R1与R2就是终结符,对应的 解析R1和R2的解释器 就是终结符表达式。通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符(R1,R2)。
  • 非终结符表达式NonTerminalExpression:实现文法中与非终结符有关的解释操作。文法中的每条规则都对应于一个非终结符表达式。非终结表达式一般是文法中的运算符或者其他关键字。
  • 上下文环境类Context:包含解释器之外的全局信息。他的任务一般是用来存放文法中各个终结符所对应的具体值。

代码示例

用解释器模式实现一个数学表达式计算器

  • 抽象表达式角色:
package com.caozz.demo2.interpreter.calculate;

public interface IArithmeticInterpreter {
    int interpret();
}
  • 非终结表达式角色抽象
package com.caozz.demo2.interpreter.calculate;

public abstract class SymbolInterpreter implements IArithmeticInterpreter {

    protected IArithmeticInterpreter left;
    protected IArithmeticInterpreter right;

    public SymbolInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
        this.left = left;
        this.right = right;
    }
}
  • 具体非终结表达式(加减乘除)
package com.caozz.demo2.interpreter.calculate;

public class AddInterpreter extends SymbolInterpreter {

    public AddInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
        super(left, right);
    }

    public int interpret() {
        return this.left.interpret() + this.right.interpret();
    }
}
package com.caozz.demo2.interpreter.calculate;

public class SubInterpreter extends SymbolInterpreter {
    public SubInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right) {
        super(left, right);
    }

    public int interpret() {
        return this.left.interpret() - this.right.interpret();
    }
}
package com.caozz.demo2.interpreter.calculate;

public class MultiInterpreter extends SymbolInterpreter {

    public MultiInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){
        super(left,right);
    }

    public int interpret() {
        return this.left.interpret() * this.right.interpret();
    }

}

package com.caozz.demo2.interpreter.calculate;

public class DivInterpreter extends SymbolInterpreter {

    public DivInterpreter(IArithmeticInterpreter left, IArithmeticInterpreter right){
        super(left,right);
    }

    public int interpret() {
        return this.left.interpret() / this.right.interpret();
    }

}

  • 终结符表达式(数字表达式)
package com.caozz.demo2.interpreter.calculate;

public class NumInterpreter implements IArithmeticInterpreter {
    private int value;

    public NumInterpreter(int value) {
        this.value = value;
    }


    public int interpret() {
        return this.value;
    }
}
  • 计算器
    parse方法对应的是不考虑优先级的,parse01是考虑优先级的
package com.caozz.demo2.interpreter.calculate;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class GPCalculator {
    private Stack<IArithmeticInterpreter> stack = new Stack<>();
    Queue<IArithmeticInterpreter> finalNum = new LinkedList<>();

    public GPCalculator(String expression) {
//        this.parse(expression);
        this.parse01(expression);
    }

    private void parse(String expression) {
        String [] elements = expression.split(" ");
        IArithmeticInterpreter leftExpr, rightExpr;

        for (int i = 0; i < elements.length ; i++) {
            String operator = elements[i];
            if (OperatorUtil.isOperator(operator)){
                leftExpr = this.stack.pop();
                rightExpr = new NumInterpreter(Integer.valueOf(elements[++i]));
                System.out.println("出栈: " + leftExpr.interpret() + " 和 " + rightExpr.interpret());
                this.stack.push(OperatorUtil.getInterpreter(leftExpr, rightExpr,operator));
                System.out.println("应用运算符: " + operator);
            }
            else{
                NumInterpreter numInterpreter = new NumInterpreter(Integer.valueOf(elements[i]));
                this.stack.push(numInterpreter);
                System.out.println("入栈: " + numInterpreter.interpret());
            }
        }
    }


    private void parse01(String expression) {
        String [] elements = expression.split(" ");
        Queue<String> symbols = new LinkedList<>();
        Queue<String> nums = new LinkedList<>();

        for (int i = 0; i < elements.length ; i++) {
            String ele = elements[i];
            if (OperatorUtil.isOperator(ele)){
                symbols.offer(ele);
            } else {
                nums.offer(ele);
            }
        }

        //先计算乘法
        Stack<String> nsymbols = new Stack<>();
        Stack<IArithmeticInterpreter> nnums = new Stack<>();
        nnums.push(new NumInterpreter(Integer.valueOf(nums.poll())));
        int symbolLen = symbols.size();
        for (int j = 0; j < symbolLen; j++) {
            String operator = symbols.poll();
            IArithmeticInterpreter next = new NumInterpreter(Integer.valueOf(nums.poll()));
            if (OperatorUtil.isAddSub(operator)) {
                nsymbols.push(operator);
                nnums.push(next);
            } else {
                IArithmeticInterpreter previous = nnums.pop();
                nnums.push(new MultiInterpreter(previous,next));
            }
        }


        //乘法计算完成后的
        int len = nsymbols.size();
        IArithmeticInterpreter first = nnums.pop();
        finalNum.offer(first);
        for (int h = 0; h < len; h++) {
            String e = nsymbols.pop();
            IArithmeticInterpreter pre = finalNum.poll();
            IArithmeticInterpreter next = nnums.pop();
            if ("+".equals(e)) {
                finalNum.offer(new AddInterpreter(pre,next));
            } else {
                finalNum.offer(new SubInterpreter(next,pre));
            }
        }
    }



    public int calculate() {
//        return this.stack.pop().interpret();
        IArithmeticInterpreter poll = this.finalNum.poll();
        return poll.interpret();
    }
}
  • 测试
package com.caozz.demo2.interpreter.calculate;

public class Test {

    public static void main(String[] args) {
        System.out.println("result(10 + 30): " + new GPCalculator("10 + 30").calculate());
        System.out.println("result(       50 + 30 - 20       ): " + new GPCalculator("50 + 30 - 20").calculate());
        System.out.println("result(        2 + 5 * 3         ): " + new GPCalculator("2 + 5 * 3").calculate());
        System.out.println("result(       2 * 3 + 4 * 5      ): " + new GPCalculator("2 * 3 + 4 * 5").calculate());
        System.out.println("result(    2 * 3 * 5 + 4 * 5     ): " + new GPCalculator("2 * 3 * 5 + 4 * 5").calculate());
        System.out.println("result(    2 * 5 + 4 * 5 * 6     ): " + new GPCalculator("2 * 5 + 4 * 5 * 6").calculate());
        //15 + 15 + 60 = 90
        System.out.println("result(3 * 5 + 6 + 9 + 2 * 3 * 10): " + new GPCalculator("3 * 5 + 6 + 9 + 2 * 3 * 10").calculate());
    }

}

  • 测试结果
D:\software\java\jdk-17.0.2\bin\java.exe ...
result(10 + 30): 40
result(       50 + 30 - 20       ): 60
result(        2 + 5 * 3         ): 17
result(       2 * 3 + 4 * 5      ): 26
result(    2 * 3 * 5 + 4 * 5     ): 50
result(    2 * 5 + 4 * 5 * 6     ): 130
result(3 * 5 + 6 + 9 + 2 * 3 * 10): 90

Process finished with exit code 0
欢迎大家留言,以便于后面的人更快解决问题!另外亦欢迎大家可以关注我的微信公众号,方便利用零碎时间互相交流。共勉!

标签:解释器,right,calculate,模式,new,设计模式,public,interpret,IArithmeticInterpreter
From: https://www.cnblogs.com/caozz/p/18262887/interpreter

相关文章

  • 设计模式之-代理模式
    代理模式是一种结构型设计模式,它允许你提供一个代理对象来控制对其他对象的访问。代理模式主要解决的问题是在某些情况下,直接访问一个对象可能会带来一些问题,比如对象的创建和销毁需要额外的开销,或者需要对对象的访问进行控制和限制。需要使用代理模式的时候,通常有以下情况:对......
  • 设计模式六大原则(一)---单一职责原则
    单一职责原则(SingleResponsibilityPrinciple,SRP)是面向对象设计中的一个原则,它要求一个类或模块应该有且只有一个引起它变化的原因。单一职责原则主要解决的问题是类的职责过于复杂,即一个类承担了过多的责任。当一个类具有多个职责时,任何一个职责的变化都可能影响到其他职责,导致......
  • java设计模式--装饰器模式
    装饰器模式是一种结构型设计模式,它允许你动态地向对象添加额外的行为。装饰器模式通过将对象包装在一个装饰器类中,以提供额外的功能,而不是修改原始对象的结构。装饰器模式主要解决的问题是在不改变现有对象结构的情况下,动态地添加功能或修改行为。它可以避免使用子类继承的方式引......
  • C++设计模式 之 Monostate模式
    目录标题第一章:Monostate模式简介什么是Monostate模式?Monostate模式的工作原理使用Monostate模式的优势适用场景第二章:实现Monostate模式基本结构构造函数和析构函数使用案例总结第三章:Monostate模式的优缺点优点缺点Monostate模式与单例模式的比较第四章:Monostate模......
  • 尚玩助手app对接广告模式开发源码搭建
    当涉及到“尚玩助手”这样的App对接广告模式并进行源码搭建时,你需要遵循一系列步骤来确保广告的有效集成和App的稳定运行。以下是一个基本的流程指南:1.明确需求和广告模式需求分析:明确App需要对接的广告类型(如横幅广告、插屏广告、视频广告等)和广告展示策略。广告模式选择:根......
  • java单例设计模式 , 多例设计模式 , 工厂设计模式概念及详细介绍
    单例设计模式正常情况下一个类可以创建多个对象publicstaticvoidmain(String[]args){ //正常情况下一个类可以创建多个对象 Personp1=newPerson(); Personp2=newPerson(); Personp3=newPerson();}如果说有时一个对象就能搞定的事情,非要创建多......
  • 《植物大战僵尸杂交版》入驻原作创意模式(附下载)
    经典塔防游戏《植物大战僵尸》自2009年5月5日发布以来,以其独特的游戏设计和趣味性深受玩家喜爱。如今,这款经典游戏再次焕发新生,迎来了一个全新版本——《植物大战僵尸杂交版》。这一版本由B站UP主“潜艇伟伟迷”精心打造,以其创新的“杂交”玩法,为玩家带来了全新的游戏体验。《......
  • GPIO的工作模式
    输入模式:输入浮空、输入上拉、输入下拉、模拟输入输出模式:开漏输出、开漏复用功能、推挽式输出、推挽式输出复用功能输入浮空:输入上拉:输入下拉:开漏输出:开漏复用功能:推挽式输出:推挽式输出复用功能:......
  • Silence 主题暗黑模式根据浏览器配置,以及切换页面闪白屏的问题处理
    最近使用Silencev3.0.0-rc2主题遇到两个偏好问题(感谢作者提供了这么好用的主题),记录下处理的过程。暗黑/亮色模式跟随浏览器的主题切换由于主题当前支持的配置项auto是根据时间定的,而不是根据浏览器的配置来的,而我个人偏向于跟随浏览器的配置来自动设置,于是用js先判断浏......
  • 尚玩助手app对接广告模式开发搭建
    尚玩助手APP对接广告模式的开发搭建主要涉及以下几个方面:需求分析:首先,需要明确尚玩助手APP的定位、目标用户群以及广告目标。这将有助于确定广告的内容和形式,以及广告投放的策略和位置1。平台选择:选择一个合适的广告联盟或广告平台进行合作。尚玩助手APP需要对接的广告平台应......