1. 程式人生 > 其它 >空值合併運算子 ??

空值合併運算子 ??

直譯器模式基本介紹

1)在編譯原理中,一個算術表示式通過詞法分析器形成詞法單元,而後這些詞法單元再通過語法分析器構建語法分析樹,最終形成一顆抽象的語法分析樹。這裡的詞法分析器和語法分析器都可以看做是直譯器
2)直譯器模式( Interpreter Pattern):是指給定一個語言(表示式),定義它的文法的一種表示,並定義一個直譯器,使用該直譯器來解釋語言中的句子(表示式)
3)應用場景

  • 應用可以將一個需要解釋執行的語言中的句子表示為一個抽象語法樹
  • 一些重複出現的問題可以用一種簡單的語言來表達
  • 一個簡單語法需要解釋的場景

4)這樣的例子還有,比如編譯器、運算表示式計算、正則表示式、機器人等

直譯器模式的原理類圖


對原理類圖的說明(直譯器模式的角色及職責)
1.Context:環境角色:含有直譯器之外的全域性資訊
2.AbstractExpression:抽象表示式,宣告一個抽象的解釋操作,這個方法為抽象語法樹中所有的節點共享
3.TerminalExpression:終結符表示式,實現與3文法中的終結符相關的解釋操作
4.NonTerminalExpression:非終結符表示式,為文法中的非終結符實現解釋操作
說明:輸入Context 和TerminalExpression資訊通過Client輸入即可

四則運算問題

通過直譯器模式模式實現四則運算,如計算a+b-c的值
1.先輸入表示式的形式,比如a+b+c-d+e,要求表示式的字母不能重複
2.再分別輸出a,b,c,d,e的值
3.最後求出結果


程式碼實現

package com.cedric.interpreter;

import java.util.HashMap;

/**
 * 抽象類表示式,通過HashMap鍵值對,可以獲取到變數的值
 */
public abstract class Expression {

    // 解釋公式和 數值,key就是公式(表示式),value就是具體值
    abstract int interpreter(HashMap<String,Integer> var);
}

package com.cedric.interpreter;

import java.util.HashMap;

/**
 * 變數的直譯器
 */
public class VarExpression  extends Expression{

    private String key;

    public VarExpression(String key){
        this.key = key;
    }

    // interpreter 根據變數名稱返回對應值
    @Override
    int interpreter(HashMap<String, Integer> var) {
        return var.get(this.key);
    }
}

package com.cedric.interpreter;

import java.util.HashMap;

/**
 * 抽象運算子號解析器,每個運算子號都之和自己左右兩個數字有關係
 * 但左右兩個數字有可能也是一個解析的結果,無論何種型別,都是Expression實現類
 */

public class SymbolExpression extends Expression{

    protected Expression left;
    protected Expression right;

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

    // 因為 SymbolExpression是其子類來實現,因此interpreter是一個預設實現
    @Override
    int interpreter(HashMap<String, Integer> var) {
        return 0;
    }
}

package com.cedric.interpreter;

import java.util.HashMap;

/**
 * 加法直譯器
 */
public class AddExpression extends SymbolExpression{

    public AddExpression(Expression left, Expression right) {
        super(left, right);
    }

    // 處理相加
    public int interpreter(HashMap<String,Integer> var){
        // super.left.interpreter(var):返回left表示式對應的值
        // super.right.interpreter(var):返回right表示式對應的值
        return super.left.interpreter(var) + super.right.interpreter(var);
    }
}

package com.cedric.interpreter;

import java.util.HashMap;

public class SubExpression extends SymbolExpression{

    public SubExpression(Expression left, Expression right) {
        super(left, right);
    }

    // 求出left和right表示式相減後的結果
    public int interpreter(HashMap<String,Integer> var){
        // super.left.interpreter(var):返回left表示式對應的值
        // super.right.interpreter(var):返回right表示式對應的值
        return super.left.interpreter(var) - super.right.interpreter(var);
    }
}

package com.cedric.interpreter;

import java.util.HashMap;
import java.util.Stack;

public class Calculator {

    // 定義表示式
    private Expression expression;

    // 建構函式傳參並解析
    public Calculator(String expStr) {
        // 安排先後順序
        Stack<Expression> stack = new Stack<>();
        // 表示式拆分成字元陣列
        char[] charArray = expStr.toCharArray();

        Expression left = null;
        Expression right = null;
        // 遍歷字元陣列
        // 針對不同情況做相應處理
        for (int i = 0; i < charArray.length; i++) {
            switch (charArray[i]) {
                case '+':
                    left = stack.pop();// 從stack取出left
                    right = new VarExpression(String.valueOf(charArray[++i]));// 去除右表示式
                    stack.push(new AddExpression(left, right));// 根據得到的left和right構建AddExpression加入stack
                    break;
                case '-':
                    left = stack.pop();
                    right = new VarExpression(String.valueOf(charArray[++i]));
                    stack.push(new AddExpression(left, right));
                default:
                    // 如果是一個Var 就建立要給VarExpression物件,並push到stack
                    stack.push(new VarExpression(String.valueOf(charArray[i])));
                    break;
            }
        }
        // 當遍歷完整個charArray陣列後,stack就得到了最後的Expression
        this.expression = stack.pop();
    }

    public int run(HashMap<String, Integer> var) {
        // 最後將表示式和var繫結
        // 然後傳遞給expression的interpreter進行解釋執行
        return this.expression.interpreter(var);
    }

}
package com.cedric.interpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;

public class ClientTest {
    public static void main(String[] args) throws IOException {

        String expStr = getExpStr();// a+b
        HashMap<String,Integer> var = getValue(expStr);// var{a = 10,b =  20}
        Calculator calculator = new Calculator(expStr);
        System.out.println("運算結果:" + expStr + "=" + calculator.run(var));
    }

    // 獲得表示式
    public static String getExpStr() throws IOException {
        System.out.println("請輸入表示式:");
        return (new BufferedReader(new InputStreamReader(System.in))).readLine();
    }

    // 獲得對映值
    public static HashMap<String,Integer> getValue(String expStr){
        HashMap<String,Integer> map = new HashMap<>();

        for(char ch : expStr.toCharArray()){
            if(ch != '+' && ch != '-'){
                break;
            }
        }

    }
}

直譯器模式的注意事項和細節

1.當有一個語言需要解釋執行,可將該語言中的句子表示為一個抽象的語法樹,就可以考慮使用直譯器模式,讓程式具有
  良好的擴充套件性
2.應用場景:編譯器、運算表示式計算、正則表示式、機器人等
3.使用直譯器模式可能帶來的問題:直譯器模式會引起類膨脹、直譯器模式採用遞迴呼叫方法 ,將會導致除錯非常複雜,效率可能降低