<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「補課」進行時:設計模式(20)——解釋器模式

          共 1867字,需瀏覽 4分鐘

           ·

          2020-12-23 02:35

          1. 前文匯總

          「補課」進行時:設計模式系列

          2. 解釋器模式

          解釋器模式這個模式和前面的訪問者模式比較像,當然,我說的比較像是難的比較像,以及使用率是真的比較低,基本上沒有使用的場景,訪問者模式還有點使用場景,解釋器模式,我們又不寫解釋器,這玩意 JVM 都幫我們實現(xiàn)掉了,哪用我們自己實現(xiàn)。

          常見的解釋器有 JVM 為我們提供的 Java 語言的解釋器,還有我們經(jīng)常使用的 MySQL ,也有內(nèi)置的 SQL 解釋器。

          不過沒用是沒用,對應的模式我們還是可以學習一下。

          2.1 定義

          解釋器模式(Interpreter Pattern) 是一種按照規(guī)定語法進行解析的方案,其定義如下:

          Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(給定一門語言, 定義它的文法的一種表示, 并定義一個解釋器, 該解釋器使用該表示來解釋語言中的句子。)

          2.2 通用類圖

          • AbstractExpression 抽象解釋器:具體的解釋任務由各個實現(xiàn)類完成, 具體的解釋器分別由 TerminalExpression 和 NonterminalExpression 完成。
          • TerminalExpression 終結(jié)符表達式:實現(xiàn)與文法中的元素相關(guān)聯(lián)的解釋操作, 通常一個解釋器模式中只有一個終結(jié)符表達式, 但有多個實例, 對應不同的終結(jié)符。
          • NonterminalExpression 非終結(jié)符表達式:文法中的每條規(guī)則對應于一個非終結(jié)表達式, 具體到我們的例子就是加減法規(guī)則分別對應到 AddExpression 和 SubExpression 兩個類。非終結(jié)符表達式根據(jù)邏輯的復雜程度而增加, 原則上每個文法規(guī)則都對應一個非終結(jié)符表達式。
          • Context 環(huán)境角色

          2.3 通用代碼

          抽象表達式

          public?abstract?class?Expression?{
          ????abstract?Object?interpreter(Context?ctx);
          }

          抽象表達式比較簡單,通常只有一個方法,但是它是生成語法集合(也叫做語法樹) 的關(guān)鍵, 每個語法集合完成指定語法解析任務, 它是通過遞歸調(diào)用的方式, 最終由最小的語法單元進行解析完成。

          終結(jié)符表達式

          public?class?TerminalExpression?extends?Expression?{
          ????//?通常終結(jié)符表達式只有一個,?但是有多個對象
          ????public?Object?interpreter(Context?context)?{
          ????????return?null;
          ????}
          }

          終結(jié)符表達式比較簡單, 主要是處理場景元素和數(shù)據(jù)的轉(zhuǎn)換。

          非終結(jié)符表達式

          public?class?NonterminalExpression?extends?Expression?{
          ????//?每個非終結(jié)符表達式都會對其他表達式產(chǎn)生依賴
          ????public?NonterminalExpression(Expression?...expressions)?{
          ????}
          ????@Override
          ????Object?interpreter(Context?ctx)?{
          ????????//?進行文法處理
          ????????return?null;
          ????}
          }

          每個非終結(jié)符表達式都代表了一個文法規(guī)則, 并且每個文法規(guī)則都只關(guān)心自己周邊的文法規(guī)則的結(jié)果(注意是結(jié)果) , 因此這就產(chǎn)生了每個非終結(jié)符表達式調(diào)用自己周邊的非終結(jié)符表達式, 然后最終、 最小的文法規(guī)則就是終結(jié)符表達式, 終結(jié)符表達式的概念就是如此,不能夠再參與比自己更小的文法運算了。

          客戶端

          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????Context?ctx?=?new?Context();
          ????????Stack?stack?=?null;
          ????????for(int?i?=?0;?i?????????????//?進行語法判斷,?并產(chǎn)生遞歸調(diào)用
          ????????}
          ????????//?產(chǎn)生一個完整的語法樹,?由各個具體的語法分析進行解析
          ????????Expression?exp?=?stack.pop();
          ????????//具體元素進入場景
          ????????exp.interpreter(ctx);
          ????}
          }

          2.4 優(yōu)點

          解釋器是一個簡單語法分析工具, 它最顯著的優(yōu)點就是擴展性, 修改語法規(guī)則只要修改相應的非終結(jié)符表達式就可以了, 若擴展語法, 則只要增加非終結(jié)符類就可以了。

          2.5 缺點

          • 解釋器模式會引起類膨脹。
          • 解釋器模式采用遞歸調(diào)用方法,將會導致調(diào)試非常復雜。
          • 使用了大量的循環(huán)和遞歸,效率是一個不容忽視的問題。

          3. 四則運算

          簡單使用解釋器模式實現(xiàn)一下加減法運算。

          首先定義一個計算類,用作解析器封裝:

          public?class?Calculator?{
          ????private?Expression?expression;

          ????//?構(gòu)造函數(shù),傳參并解析
          ????public?Calculator(String?expStr)?{
          ????????//?安排運算先后順序
          ????????Stack?stack?=?new?Stack<>();
          ????????//?表達式拆分為字符數(shù)組
          ????????char[]?charArray?=?expStr.toCharArray();

          ????????Expression?left?=?null;
          ????????Expression?right?=?null;

          ????????for(int?i=0;?i????????????switch?(charArray[i])?{
          ????????????????case?'+':
          ????????????????????left?=?stack.pop();
          ????????????????????right?=?new?VarExpression(String.valueOf(charArray[++i]));
          ????????????????????stack.push(new?AddExpression(left,?right));
          ????????????????????break;
          ????????????????case?'-':
          ????????????????????left?=?stack.pop();
          ????????????????????right?=?new?VarExpression(String.valueOf(charArray[++i]));
          ????????????????????stack.push(new?SubExpression(left,?right));
          ????????????????????break;
          ????????????????default?:
          ????????????????????stack.push(new?VarExpression(String.valueOf(charArray[i])));
          ????????????????????break;
          ????????????}
          ????????}
          ????????this.expression?=?stack.pop();
          ????}

          ????public?int?run(HashMap?var)?{
          ????????return?this.expression.interpreter(var);
          ????}
          }

          接下來是一個抽象表達式:

          public?abstract?class?Expression?{
          ????abstract?int?interpreter(HashMap?var);
          }

          下面是一個變量解析器:

          public?class?VarExpression?extends?Expression?{
          ????private?String?key;
          ????public?VarExpression(String?key)?{
          ????????this.key?=?key;
          ????}
          ????@Override
          ????int?interpreter(HashMap?var)?{
          ????????return?var.get(this.key);
          ????}
          }

          變量解析器的主要作用是從 map 中將數(shù)據(jù)一個一個取出來。

          接下來是一個抽象運算符號解析器:

          public?class?SymbolExpression?extends?Expression?{
          ????protected?Expression?left;
          ????protected?Expression?right;

          ????public?SymbolExpression(Expression?left,?Expression?right)?{
          ????????this.left?=?left;
          ????????this.right?=?right;
          ????}
          ????@Override
          ????int?interpreter(HashMap?var)?{
          ????????return?0;
          ????}
          }

          因為是運算符號,而每個運算符號都只和自己左右兩個數(shù)字有關(guān)系,左右兩個數(shù)字有可能也是一個解析的結(jié)果,無論何種類型,都是 Expression 類的實現(xiàn)類。

          接下來是兩個具體的運算符號解析器,一個加號解析器和一個減號解析器:

          public?class?AddExpression?extends?SymbolExpression?{
          ????public?AddExpression(Expression?left,?Expression?right)?{
          ????????super(left,?right);
          ????}

          ????@Override
          ????int?interpreter(HashMap?var)?{
          ????????return?super.left.interpreter(var)?+?super.right.interpreter(var);
          ????}
          }

          public?class?SubExpression?extends?SymbolExpression?{
          ????public?SubExpression(Expression?left,?Expression?right)?{
          ????????super(left,?right);
          ????}

          ????@Override
          ????int?interpreter(HashMap?var)?{
          ????????return?super.left.interpreter(var)?-?super.right.interpreter(var);
          ????}
          }

          最后是我們的客戶端類:

          public?class?Client?{
          ????public?static?void?main(String[]?args)?throws?IOException?{
          ????????String?expStr?=?getExpStr();
          ????????HashMap?var?=?getValue(expStr);
          ????????Calculator?calculator?=?new?Calculator(expStr);
          ????????System.out.println("運算結(jié)果:"?+?expStr?+?"="?+?calculator.run(var));
          ????}

          ????public?static?String?getExpStr()?throws?IOException?{
          ????????System.out.print("請輸入表達式:");
          ????????return?(new?BufferedReader(new?InputStreamReader(System.in))).readLine();
          ????}

          ????public?static?HashMap?getValue(String?expStr)?throws?IOException?{
          ????????HashMap?map?=?new?HashMap<>();
          ????????for(char?ch?:?expStr.toCharArray())?{
          ????????????if(ch?!=?'+'?&&?ch?!=?'-'?)?{
          ????????????????if(!?map.containsKey(String.valueOf(ch)))?{
          ????????????????????System.out.print("請輸入"?+?String.valueOf(ch)?+?"的值:");
          ????????????????????String?in?=?(new?BufferedReader(new?InputStreamReader(System.in))).readLine();
          ????????????????????map.put(String.valueOf(ch),?Integer.valueOf(in));
          ????????????????}
          ????????????}
          ????????}
          ????????return?map;
          ????}
          }

          執(zhí)行結(jié)果如下:

          請輸入表達式:a+b-c
          請輸入a的值:10
          請輸入b的值:20
          請輸入c的值:13
          運算結(jié)果:a+b-c=17

          解釋器模式在實際的系統(tǒng)開發(fā)中使用得非常少, 因為它會引起效率、 性能以及維護等問題, 一般在大中型的框架型項目能夠找到它的身影, 如一些數(shù)據(jù)分析工具、 報表設計工具、科學計算工具等。

          如果遇到確定要使用解析器的場景,可以考慮一下 Expression4J 、 MESP(Math Expression String Parser) 、 Jep 等開源的解析工具包,功能都異常強大,而且非常容易使用,效率也還不錯, 實現(xiàn)大多數(shù)的數(shù)學運算沒有問題,完全自己沒有必要從頭開始編寫解釋器。





          感謝閱讀



          瀏覽 56
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  麻豆91在线 | 婷婷久久丁香 | 无码一区二区黑人猛烈视频网站 | 国产青青草视频 | 亚洲黄色电影在线看 |