Android設計模式之——解釋器模式

一、介紹

解釋器模式(Interpreter Pattern)是一種用的比較少的行為型模式,其提供了一種解釋語言的語法或表達式的方式,該模式定義了一個表達式接口,通過該接口解釋一個特定的上下文。在這么多的設計模式中,解釋器模式在實際運用上相對來說要少很多,因為我們很少會自己去構造一個語言的文法。雖然如此,既然它能夠在設計模式中有一席之位,那么必定有它的可用之處。

二、定義

給定一個語言,定義它的文法的一種表示,并定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。(其中語言就是我們需要解釋的對象,文法就是這個語言的規律,解釋器就是翻譯機,通過文法來翻譯語言。)

三、使用場景

  • 如果某個簡單的語言需要解釋執行而且可以將該語言中的語句表示為一個抽象的語法樹時可以考慮使用解釋器模式。

  • 在某些特定的領域出現不斷重復的問題時,可以將該領域的問題轉化為一種語法規則下的語句,然后構建解釋器來解釋該語句。

四、解釋器模式的UML類圖

UML類圖:

這里寫圖片描述

角色介紹:

  • AbstractExpression:抽象表達式,聲明一個抽象的解釋操作父類,并定義一個抽象的 interpret() 解釋方法,其具體的實現在各個具體的子類解釋器中完成。

  • TerminalExpression:終結符表達式,實現了抽象表達式角色所要求的接口,主要是一個interpret()方法;文法中的每一個終結符都有一個具體終結表達式與之相對應。比如有一個簡單的公式R=R1+R2,在里面R1和R2就是終結符,對應的解析R1和R2的解釋器就是終結符表達式。

  • NonterminalExpression:非終結符表達式,文法中的每一條規則都需要一個具體的非終結符表達式,非終結符表達式一般是文法中的運算符或者其他關鍵字,比如公式R=R1+R2中,“+”就是非終結符,解析“+”的解釋器就是一個非終結符表達式。

  • Context:上下文環境類,這個角色的任務一般是用來存放文法中各個終結符所對應的具體值,比如R=R1+R2,我們給R1賦值100,給R2賦值200。這些信息需要存放到環境角色中,很多情況下我們使用Map來充當環境角色就足夠了。

  • Client:客戶類,解析表達式,構建抽象語法樹,執行具體的解釋操作等。

通用代碼如下:

/*** 抽象表達式*/
public abstract class AbstractExpression {/*** 抽象的解析方法* @param context 上下文環境對象*/public abstract void interpret(Context context);
}/*** 終結符表達式*/
public class TerminalExpression extends AbstractExpression{@Overridepublic void interpret(Context context) {//實現文法中與終結符有關的解釋操作}
}/*** 非終結符表達式*/
public class NonterminalExpression extends AbstractExpression{@Overridepublic void interpret(Context context) {//實現文法中與非終結符有關的解釋操作}
}/*** 上下文環境類*/
public class Context {
}/*** 客戶類*/
public class Client {public static void main(String[] args) {//根據文法對特定句子構建抽象語法樹后解釋}
}

五、簡單實現

我們使用解釋器模式對“m+n+p”這個表達式進行解釋,那么代表數字的m、n和p就可以看成終結符號,而“+”這個運算符號可以當做非終結符號。

抽象的算數運算解釋器:

public abstract class ArithemticExpression {/*** 抽象的解析方法 * 具體的解析邏輯由具體的子類實現* * @return 解析得到具體的值*/public abstract int interpreter();
}

數字解釋器:

public class NumExpression extends ArithemticExpression{private int num;public NumExpression(int num){this.num = num;}@Overridepublic int interpreter() {return num;}
}

運算符號解釋器:

public abstract class OperatorExpression extends ArithemticExpression{protected ArithemticExpression exp1, exp2;public OperatorExpression(ArithemticExpression exp1, ArithemticExpression exp2){this.exp1 = exp1;this.exp2 = exp2;}
}

具體的加法運算符解釋器:

public class AdditionExpression extends OperatorExpression{public AdditionExpression(ArithemticExpression exp1,ArithemticExpression exp2) {super(exp1, exp2);}@Overridepublic int interpreter() {return exp1.interpreter() + exp2.interpreter();}}

處理解釋器:

public class Calculator {//聲明一個Stack棧儲存并操作所有相關的解釋器private Stack<ArithemticExpression> mExpStack = new Stack<ArithemticExpression>();public Calculator(String expression){//聲明兩個ArithemticExpression類型的臨時變量,儲存運算符左右兩邊的數字解釋器ArithemticExpression exp1,exp2;//根據空格分割表達式字符串(比如1 + 2 + 3 + 4)String[] elements = expression.split(" ");/** 遍歷表達式元素數組*/for(int i = 0; i < elements.length; i++){/** 判斷運算符號*/switch (elements[i].charAt(0)) {case '+'://如果是加號,則將棧中的解釋器彈出作為運算符號左邊的解釋器exp1 = mExpStack.pop();//同時將運算符號數組下標的下一個元素構造為一個數字解釋器exp2 = new NumExpression(Integer.parseInt(elements[++i]));//通過上面的兩個數字解釋器構造加法運算解釋器 mExpStack.push(new AdditionExpression(exp1, exp2));break;default:/** 如果為數字,直接構造數字解釋器并壓入棧*/mExpStack.push(new NumExpression(Integer.valueOf(elements[i])));break;}}}/*** 計算結果* * @return 最終的計算結果*/public int calculate(){return mExpStack.pop().interpreter();}
}

調用:

public class Client {public static void main(String[] args) {Calculator c = new Calculator("22 + 553 + 83 + 5");System.out.println("計算結果:"+c.calculate());}
}

結果:

計算結果:663

如果相加如減法的操作,在Calculator中加入相應判斷即可:

public class SubtractionExpression extends OperatorExpression{public SubtractionExpression(ArithemticExpression exp1,ArithemticExpression exp2) {super(exp1, exp2);}@Overridepublic int interpreter() {return exp1.interpreter() - exp2.interpreter();}}

Calculator中加入:

case '-':exp1 = mExpStack.pop();exp2 = new NumExpression(Integer.parseInt(elements[++i]));mExpStack.push(new SubtractionExpression(exp1, exp2));break;

從上面可以看出解釋器模式很靈活,他將復雜問題可以簡單化、模塊化、分離實現、解釋執行。

六、Android源碼中解釋器模式

1、PackageParser

PackageParser是對AndroidManifest.xml配置文件進行讀取的,具體原理參考:解析AndroidManifest原理

七、總結

優點:

  • 最大的優點使其靈活的擴展性,當我們想對文法規則進行擴展延伸時,只需要增加相應的非終結符解釋器,并在構建抽象語法樹時,使用到新增的解釋器對象進行具體的解釋即可,非常方便。

缺點:

  • 每個語法都要產生一個非終結符表達式,語法規則比較復雜時,就可能產生大量的類文件,為維護帶來了非常多的麻煩。

  • 解釋器模式由于使用了大量的循環和遞歸,效率是個問題,特別是用于解析復雜、冗長的語法時,效率是難以忍受的。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447014.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447014.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447014.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在Docker里面安裝Ubuntu,并且使用ssh進行連接

創建Ubuntu鏡像 1&#xff0c;拉取Ubuntu系統的鏡像 docker pull ubuntu2、查看拉取是否成功 docker images3&#xff0c;運行容器 docker run --name 新建的容器的名字 -ti -v /AAA:/BBB -d -p 3316:22 ubuntu(這個是鏡像的名字)宿主機根目錄中的AAA文件夾就映射到了容器…

Android設計模式之——命令模式

一、介紹 命令模式&#xff08;Command Pattern&#xff09;&#xff0c;是行為型設計模式之一。命令模式相對于其他的設計模式來說并沒有那么多的條條框框&#xff0c;其實它不是一個很”規范“的模式&#xff0c;不過&#xff0c;就是基于這一點&#xff0c;命令模式相對于其…

C++ 序列化和反序列化學習

定義 程序員在編寫應用程序的時候往往需要將程序的某些數據存儲在內存中&#xff0c;然后將其寫入某個文件或是將它傳輸到網絡中的另一臺計算機上以實現通訊。這些過程將會涉及到程序數據轉化成能被存儲并傳輸的格式&#xff0c;因此被稱為“序列化”&#xff08;Serializatio…

Android設計模式之——觀察者模式

一、介紹 觀察者模式是一個使用率非常高的模式&#xff0c;它最常用的地方是GUI系統、訂閱——發布系統。因為這個模式的一個重要作用就是解耦&#xff0c;將被觀察者和觀察者解耦&#xff0c;使得它們之間的依賴性更小&#xff0c;甚至做到毫無依賴。以GUI系統來說&#xff0…

Android設計模式之——備忘錄模式

一、介紹 備忘錄模式是一種行為模式&#xff0c;該模式用于保存對象當前狀態&#xff0c;并且在之后可以再次恢復到此狀態&#xff0c;這有點像我們平時說的”后悔藥“。備忘錄模式實現的方式需要保證被保存的對象狀態不能被對象從外部訪問&#xff0c;目的是為了保護好被保存…

c++ memory 頭文件詳細介紹

類 指針特征 pointer_traits (C11) 提供關于指針式類型的信息 (類模板) 垃圾收集器支持 pointer_safety (C11) 列出指針安全模式 (枚舉) 分配器 allocator 默認的分配器 (類模板) allocator_traits (C11) 提供關于分配器類型的信息 (類模板) allocator_arg_t (C11) 標簽類型…

C++ using的三種使用策略以及具體的用法

Using的使用方法 1&#xff0c;命名空間的使用 為了防止代碼沖突&#xff0c;都會使用到命名空間。假設這樣一種情況&#xff0c;當一個班上有兩個名叫 Zara 的學生時&#xff0c;為了明確區分他們&#xff0c;我們在使用名字之外&#xff0c;不得不使用一些額外的信息&#…

Android設計模式之——迭代器模式

一、介紹 迭代器模式&#xff08;Iterator Pattern&#xff09;又稱為游標&#xff08;Cursor&#xff09;模式&#xff0c;是行為型設計模式之一。迭代器模式算是一個比較古老的設計模式&#xff0c;其源于對容器的訪問&#xff0c;比如Java中的List、Map、數組等&#xff0c…

Android設計模式之——模板方法模式

一、介紹 在面向對象開發過程中&#xff0c;通常會遇到這樣的一個問題&#xff0c;我們知道一個算法所需的關鍵步驟&#xff0c;并確定了這些步驟的執行順序&#xff0c;但是&#xff0c;某些步驟的具體實現是未知的&#xff0c;或者說某些步驟的實現是會隨著環境的變化而改變…

Android設計模式之——訪問者模式

一、介紹 訪問者模式是一種將數據操作與數據結構分離的設計模式&#xff0c;它是《設計模式》中23種設計模式中最復雜的一個&#xff0c;但它的使用頻率并不高&#xff0c;正如《設計模式》的作者GOF對訪問者模式的描述&#xff1a;大多數情況下&#xff0c;你不需要使用訪問者…

C++類模板template <class T>簡單使用方法

一個簡單的例子 兩個數比大小 如果兩個數都是int類型 class Compare_int { public :Compare(int a,int b){xa;yb;}int max( ){return (x>y)?x:y;}int min( ){return (x<y)?x:y;} private :int x,y; }; 如果兩個數是float類型 class Compare_float { public :Compare(…

Android設計模式之——中介者模式

一、介紹 中介者模式&#xff08;Mediator Pattern&#xff09;也稱為調解者模式或調停者模式&#xff0c;Mediator本身就有調停者和調解者的意思。 在日常生活中調停者或調解者這個角色我們見得比較多的是“和事老”&#xff0c;也就是說調解兩個有爭端的人的角色&#xff0…

C++智能指針中unique_ptr部分內容的講解

參考鏈接 std::unique_ptr 介紹 定義位于頭文件<memory>std::unique_ptr 是通過指針占有并管理另一對象&#xff0c;并在 unique_ptr 離開作用域時釋放該對象的智能指針。 在下列兩者之一發生時用關聯的刪除器釋放對象&#xff1a;1&#xff0c;銷毀了管理的 unique_pt…

Java基礎——Java多線程中sleep()、wait()和notify()

一、sleep()sleep()方法源碼&#xff1a;/** * Causes the currently executing thread to sleep (temporarily cease * execution) for the specified number of milliseconds, subject to * the precision and accuracy of system timers and schedulers. The thread * does …

Key_handle的學習

代碼 一切盡在不言中 #pragma once#include "common/common.h" #include "sdf/sdf.h"#include <memory>namespace sdf {namespace algorithm {class KeyHandle {public:using erased_internal_data_t char; //使用erased_internal_data_t等效于ch…

Java基礎——虛擬機結構

一、Java平臺結構圖二、JVM、JRE和JDK關系JVM&#xff1a;Java Virtual Machine&#xff08;Java虛擬機&#xff09;&#xff0c;負責執行符合規范的Class文件 JRE&#xff1a; Java Runtime Environment &#xff08;java運行環境&#xff09;&#xff0c;包含JVM和類庫 JDK&a…

解決 SSH Connection closed by foreign host 問題

用 Xshell 連接服務器總是報錯 : Connection closed by foreign host.Disconnected from remote host... 原因可能是 SSH 服務器沒設置保活時間間隔 , 具體設置如下 : 操作 # vim /etc/ssh/sshd_config 添加兩行 , 或去掉注釋 : ClientAliveInterval 60ClientAliveCountMax…

Java基礎——synchronized

synchronized重要&#xff01;重要&#xff01;重要&#xff01;重要的事情說三遍&#xff0c;一定要記下來哦。 Java語言的關鍵字&#xff0c;當它用來修飾一個方法或者一個代碼塊的時候&#xff0c;能夠保證在同一時刻最多只有一個線程執行該段代碼。一、當兩個并發線程訪問同…

C++:MAC安裝Boost庫文件并且使用CLion開發

boost的filestem庫 C在17版本的標準庫中引入了一個filesystem庫&#xff0c;用來處理文件路徑&#xff0c;以及文件訪問。很多編譯器對filesystem庫的支持還不是很好。為了解決這個問題&#xff0c;可以臨時使用boost::filesystem來替代。其實C17標準中的filesystem庫就是從bo…

Java基礎——Java異常處理機制

一、引言 try…catch…finally恐怕是大家再熟悉不過的語句了&#xff0c;而且感覺用起來也是很簡單&#xff0c;邏輯上似乎也是很容易理解。不過&#xff0c;我親自體驗的“教訓”告訴我&#xff0c;這個東西可不是想象中的那么簡單、聽話。不信&#xff1f;那你看看下面的代碼…