软件设计模式----解释器模式(使用频率较低)

解释器模式是一种行为设计模式,用于构建语言解释器,通过定义文法和解释器,解决特定场景下频繁出现的问题。该模式描述了如何用面向对象的方式构建简单语言,包括抽象表达式、终结符表达式、非终结符表达式和环境类。解释器模式适用于文法简单且效率不是关键的情况,例如数学运算解释器。尽管它易于扩展和改变文法,但对于复杂文法的维护并不理想。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解释器模式

1、模式动机

如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题。
解释器模式描述了如何构成一个简单的语言解释器,主要应用在使用面向对象语言开发的编译器中。
在这里插入图片描述

2、模式定义

解释器模式(Interpreter Pattern) :定义语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”意思是使用规定格式和语法的代码,它是一种类行为型模式。

模式结构

在这里插入图片描述

模式角色

AbstractExpression: 抽象表达式
TerminalExpression: 终结符表达式
NonterminalExpression: 非终结符表达式
Context: 环境类
Client: 客户类

3、模式分析

解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。

  • 文法规则实例:
    expression ::= value | symbol
    symbol ::= expression ‘+’ expression | expression ‘-’ expression
    value ::= an integer //一个整数值
    在文法规则定义中可以使用一些符号来表示不同的含义,如使用“|”表示或,使用“{”和“}”表示组合,使用“*”表示出现0次或多次等,其中使用频率最高的符号是表示或关系的“|” 。
  • 抽象语法树:
    除了使用文法规则来定义一个语言,在解释器模式中还可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构成,每一棵抽象语法树对应一个语言实例。
    在这里插入图片描述
    抽象语法树描述了如何构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符类。
    在解释器模式中,每一种终结符和非终结符都有一个具体类与之对应,正因为使用类来表示每一个语法规则,使得系统具有较好的扩展性和灵活性。
  • 典型的抽象表达式类实现代码:
    在这里插入图片描述
  • 典型的终结符表达式类实现代码:
    在这里插入图片描述
  • 典型的非终结符表达式类实现代码
    在这里插入图片描述
  • 典型的环境类实现代码:
    在这里插入图片描述

4、模式的案例与分析

  • 实例:数学运算解释器
    现需要构造一个语言解释器,使得系统可以执行整数间的乘、除和求模运算。如用户输入表达式“3 * 4 / 2 % 4”,输出结果为2。使用解释器模式实现该功能。
    在这里插入图片描述
    在这里插入图片描述
package 解释器模式2;
//抽象表达式类  抽象结点
public interface Node {
    public int interpret();
}

package 解释器模式2;
//非终结符表达式 乘法节点类
public class MulNode extends SymbolNode {

    public MulNode(Node left, Node right) {
        super(left, right);
    }

    @Override
    public int interpret() {

        return super.left.interpret() * super.right.interpret();
    }
}

package 解释器模式2;
//非终结符表达式  求模表达式
public class ModNode extends SymbolNode {
    public ModNode(Node left, Node right) {
        super(left, right);
    }

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

package 解释器模式2;
//非终结符表达式 除法节点类
public class DivNode extends SymbolNode {

    public DivNode(Node left, Node right) {
        super(left, right);
    }

    @Override
    public int interpret() {
        return super.left.interpret()/super.right.interpret();

    }
}

package 解释器模式2;
//抽象非终结符表达式
public abstract class SymbolNode implements Node {
    protected Node left;
    protected Node right;

    public SymbolNode(Node left, Node right) {
        this.left = left;
        this.right = right;
    }
}


package 解释器模式2;
//终结符表达式类 (值节点类)
public class ValueNode implements Node {

    private int value;

    public ValueNode(int value){
        this.value = value;
    }
    @Override
    public int interpret() {
        return this.value;
    }
}

package 解释器模式2;

import java.util.Stack;

public class Calculator {
    private String statement;
    private Node node;

    public void build(String statement){
        Node left = null,right=null;
        Stack stack = new Stack();

        String[] statementArr = statement.split(" ");
        for(int i=0;i<statementArr.length;i++){
            if(statementArr[i].equalsIgnoreCase("*")){
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new MulNode(left,right));
            }else if(statementArr[i].equalsIgnoreCase("/")){
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new DivNode(left,right));
            }else if(statementArr[i].equalsIgnoreCase("%")){
                left = (Node) stack.pop();
                int val = Integer.parseInt(statementArr[++i]);
                right = new ValueNode(val);
                stack.push(new ModNode(left,right));
            }else{
                stack.push(new ValueNode(Integer.parseInt(statementArr[i])));
            }
        }
        this.node = (Node) stack.pop();
    }

    public int compute(){
        return node.interpret();
    }
}


package 解释器模式2;

public class Client {
    public static void main(String[] args) {
        String statement = "3 * 4 / 2 % 4";
        Calculator calculator = new Calculator();
        calculator.build(statement);
        int result = calculator.compute();
        System.out.println(statement + " = "+ result);
    }
}

在这里插入图片描述

5、模式的优缺点

优点
  • 易于改变和扩展文法。
  • 易于实现文法。
  • 增加了新的解释表达式的方式。
缺点
  • 对于复杂文法难以维护。
  • 执行效率较低。
  • 应用场景很有限。

6、模式使用环境

  • 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
  • 一些重复出现的问题可以用一种简单的语言来进行表达。
  • 文法较为简单。
  • 效率不是关键问题。
模式应用

(1) 解释器模式在使用面向对象语言实现的编译器中得到了广泛的应用,如Smalltalk语言的编译器。
(2) 目前有一些基于Java抽象语法树的源代码处理工具,如在Eclipse中就提供了Eclipse AST,它是Eclipse JDT的一个重要组成部分,用来表示Java语言的语法结构,用户可以通过扩展其功能,创建自己的文法规则。
(3) 可以使用解释器模式,通过C++、Java、C#等面向对象语言开发简单的编译器,如数学表达式解析器、正则表达式解析器等,用于增强这些语言的功能,使之增加一些新的文法规则,用于解释一些特定类型的语句。

模式扩展
  • 数学表达式解析器简介
    Expression4J:Expression4J是一个基于Java的开源框架,它用于对数学表达式进行操作,是一个数学公式解析器,在Expression4J中可以将数学表达式存储在字符串对象中。Expression4J是高度定制的,用户可以自定义文法,其主要功能包括实数和复数的基本数学运算,支持基本数学函数、复杂函数以及用户使用Java语言自定义的函数和文法,还可以定义函数目录(函数集)、支持XML配置文件等。
    http://www.expression4j.org/

Jep:Jep(Java Mathematical Expression Parser)是一个用于解析和求解数学表达式的Java类库。通过使用Jep提供的包,我们可以输入一个以字符串表示的任意数学公式,然后立即对其进行求解。Jep支持用户自定义变量、常量和自定义函数,同时还包含了大量通用的数学函数和常量。
http://www.singularsys.com/jep/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值