Design Patterns Interpreter Pattern Notes

illustrate

Record the writing method of learning design pattern-interpreter pattern. The JDK version used is version 1.8.

Interpreter(interpreter)

Intent : Define a language, define a representation of its grammar, and define an interpreter that uses that representation to interpret sentences in the language.
Structure :
Insert image description here

in:

  • AbstractExpression declares the interpretation operation of a program. This interface is shared by all nodes in the abstract syntax tree.
  • TerminalExpression implements the interpretation operations associated with terminal symbols in a grammar; each terminal symbol in a sentence requires an instance of this class.
  • NonterminalExpression requires a NonterminalExpression class for each rule in the grammar; maintains an instance variable of the AbstractExpression type for each symbol; and implements the interpretation (Interpret) operation for the nonterminal symbols in the grammar.
  • Context contains some global information outside the interpreter.
  • The Client constructs (or is given) an abstract syntax tree that represents a specific sentence in the language defined by this grammar. The abstract syntax tree is assembled from instances of NonterminaExpression and TerminalExpression; calls the interpret operation.

applicability:

  • When the language's grammar is simple and execution efficiency is not a critical issue.
  • When a problem reoccurs and can be expressed in a simple language.
  • When a language needs to be interpreted and executed, and sentences in the language can be represented as an abstract syntax tree.

Table of contents

Insert image description here

Interpreter pattern example class diagram

Insert image description here
Implement the Interpreter pattern example with this UML class diagram.

abstract expression class

package com.example.deesign_patterns.interpreter;

//抽象表达式类
public abstract class AbstractExpression {
    
    

    public abstract int interpret(Context context);
}

Environmental role class

package com.example.deesign_patterns.interpreter;

import java.util.HashMap;
import java.util.Map;

//环境角色类
public class Context {
    
    

    //定义一个map集合,用来存储变量及对应的值
    private Map<Variable,Integer> map=new HashMap<Variable,Integer>();

    //添加变量的功能
    public void assign(Variable var,Integer value){
    
    
        map.put(var,value);
    }

    //根据变量获取对应的值
    public int getValue(Variable var){
    
    
        return map.get(var);
    }
}

class that encapsulates variables

package com.example.deesign_patterns.interpreter;

//封装变量的类
public class Variable extends AbstractExpression{
    
    

    //声明存储变量名的成员变量
    private String name;

    public Variable(String name) {
    
    
        this.name = name;
    }

    @Override
    public int interpret(Context context) {
    
    
        //直接返回变量的值
        return context.getValue(this);
    }

    @Override
    public String toString() {
    
    
        return name;
    }
}

Addition expression class

package com.example.deesign_patterns.interpreter;

//加法表达式类
public class Plus extends AbstractExpression{
    
    

    //加号左边的表达式
    private AbstractExpression left;
    //加号右边的表达式
    private AbstractExpression right;

    public Plus(AbstractExpression left, AbstractExpression right) {
    
    
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
    
    
        //将左边表达式的结果和右边表达式的结果进行相加
        return left.interpret(context)+right.interpret(context);
    }

    @Override
    public String toString() {
    
    
        return "("+left.toString()+"+"+right.toString()+")";
    }
}

Subtraction expression class

package com.example.deesign_patterns.interpreter;

//减法表达式类
public class Minus extends AbstractExpression{
    
    

    //减法左边的表达式
    private AbstractExpression left;
    //减法右边的表达式
    private AbstractExpression right;

    public Minus(AbstractExpression left, AbstractExpression right) {
    
    
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret(Context context) {
    
    
        //将左边表达式的结果和右边表达式的结果进行相减
        return left.interpret(context)-right.interpret(context);
    }

    @Override
    public String toString() {
    
    
        return "("+left.toString()+"-"+right.toString()+")";
    }
}

Test class

package com.example.deesign_patterns.interpreter;

//测试类
public class Client {
    
    

    public static void main(String[] args) {
    
    
        //创建环境对象
        Context context=new Context();
        //创建多个变量对象
        Variable a=new Variable("a");
        Variable b=new Variable("b");
        Variable c=new Variable("c");
        Variable d=new Variable("d");
        //将变量存储到环境对象中
        context.assign(a,1);
        context.assign(b,2);
        context.assign(c,3);
        context.assign(d,4);
        //获取抽象语法树,如:(a-((b-c)+d))
        AbstractExpression expression=new Minus(a,new Plus(new Minus(b,c),d));
        //解释(计算)
        int result=expression.interpret(context);
        System.out.println(expression+"="+result);
    }
}

Insert image description here

benefit:

  • Easy to change and extend the grammar. Since classes are used in the solver pattern to represent the grammar rules of the language, the grammar can be changed or extended through mechanisms such as inheritance. Each grammar rule can be expressed as a class, so a simple language can be easily implemented.
  • Implementing grammars is easier. The implementation of each expression node class in the abstract syntax tree is similar, and the code writing of these classes is not particularly complicated.
  • It is more convenient to add new interpretation expressions. If the user needs to add a new interpretation expression, he only needs to add a new terminal expression or non-terminal expression class. The original expression class code does not need to be modified, and it complies with the "opening and closing principle".

shortcoming:

  • It is difficult to maintain complex grammars. In the interpreter mode, each rule needs to define at least one class. Therefore, if a language contains too many grammar rules, the number of classes will increase dramatically, making the system difficult to manage and maintain.
  • Execution efficiency is low. Because a large number of loops and recursive calls are used in the interpreter mode, it is very slow when interpreting more complex sentences, and the debugging process of the code is also more troublesome.

Guess you like

Origin blog.csdn.net/weixin_48040732/article/details/131373953