設計模式--直譯器模式Interpreter(行為型)
1 定義:
1.1 定義:Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(給定一門語言,定義它的方法的一種表示,並定義一個直譯器,該直譯器使用表示來解釋語言中的句子。)
1.2 通用類圖:
角色說明:
AbstractExpression——抽象直譯器
具體的解釋任務由各個子類完成,然而首先通過它,來向下遞迴解析。
TerminalExpression——終結符表示式
實現與文法中的元素相關聯的解釋操作,通常一個直譯器模式中只有一個終結符表示式(類),但有多個例項,對應不同的終結符。
NonterminalExpression——非終結符表示式
文法中的每條規則對應於一個非終結符表示式(類)(例如:加減法規則分別對應到AddExpression, SubExpression兩個類)。非終結符表示式根據邏輯的複雜程度而增加,原則上每個文法規則都對應一個非終結符表示式。
Context——環境角色
直譯器之外的一些全域性資訊(多為:終結符與值的對映表)。
Client——客戶角色
構建表示該方法定義的語言中的一個特定的句子的抽象語法樹,並呼叫解釋操作
執行流程:將一個待解析的輸入語句構建成一個抽象語法樹(該語法樹此時由直譯器中定義的表示式構成),然後將該語法樹(表示式)交給表示式物件去解釋(當然是遞迴的)。
1.3 通用程式碼:
public abstract class Expression {
// 每個表示式必須有一個解析任務
public abstract Object interpreter(Context ctx);
}
public class TerminalExpression extends Expression {
// 通常終結符表示式只有一個,但是有多個物件
public Object interpreter(Context ctx) {
return null;
}
}
public class NonterminalExpression extends Expression {
// 每個非終結符表示式都會對其他表示式產生依賴
public NonterminalExpression(Expression... expression) {
}
public Object interpreter(Context ctx) {
// 進行文法處理
return null;
}
}
public class Context {
}
public class Client {
public static void main(String[] args) {
Context ctx = new Context();
// 通常定一個語法容器,容納一個具體的表示式,通常為ListArray,LinkedList,Stack等型別
Stack<Expression> stack = null;
/*
* for(;;){ //進行語法判斷,併產生遞迴呼叫 }
*/
// 產生一個完整的語法樹,由各各個具體的語法分析進行解析
Expression exp = stack.pop();
// 具體元素進入場景
exp.interpreter(ctx);
}
}
2 優點
直譯器是一個簡單語法分析工具,它最顯著的特點就是擴充套件性,修改語法規則只要修改相應的非終結符表示式就可以了,若擴充套件語法,則只要增加非終結符類就可以了。
3 缺點
3.1 類膨脹:每個語法都要產生一個非終結符表示式,語法規則比較複雜時,就可能產生大量的類檔案,為維護帶來了非常多的麻煩;
3.2 不便於除錯:因為採用遞迴呼叫,若要排查錯誤,則非常複雜;
3.3 效率問題:由於使用了大量的迴圈和遞迴,效率是一個不容忽視的問題。
4 應用場景
4.1 重複發生的問題可以使用直譯器模式:如伺服器日誌檔案的分析處理;
4.2 簡單語法需要解釋:不過已逐步被被專用工具所取代;
5 注意事項
儘量不要在重要的模組中使用直譯器模式,否則維護是一個很大的問題。在專案中可以使用shell、JRuby、Groovy等指令碼語言來代替直譯器模式,彌補Java編譯型語言的不足。(而且已有眾多開源直譯器,沒必要自己寫。)
6 擴充套件
暫無
7 範例
圖1
很簡單的一個類圖,VarExpression用來解析運算元素,各個公式能運算元素的數量是不同的,但每個運算元素都對應一個VarExpression物件。SybmolExpression負責運算子號解析,由兩個子類AddExpression(負責加法運算)和SubExpression(負責減法運算)來實現。解析的工作完成了,我們還需要把安排執行的先後順序(加減法是不用考慮,但是乘除法呢?注意擴充套件性),並且還要返回結果,因此我們需要增加一個封裝類來進行封裝處理,由於我們只做運算,暫時還不與業務有關聯,定義為Calculator類,分析到這裡,思路就比較清晰了,優化後加減法類圖如圖27-2所示。
圖2
優化後加減法類圖
圖27-3 完整加減法類圖
原始碼如下:
- /**
- * @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
- * all. 抽象表示式
- */
- public abstract class Expression {
- // 解析公式和數值,其中var中的key值是是公式中的引數,value值是具體的數字
- public abstract int interpreter(HashMap<String, Integer> var);
- }
- public class VarExpression extends Expression {
- private String key;
- public VarExpression(String _key) {
- this.key = _key;
- }
- // 從map中取之
- public int interpreter(HashMap<String, Integer> var) {
- return var.get(this.key);
- }
- }
- public abstract class SymbolExpression extends Expression {
- protected Expression left;
- protected Expression right;
- // 所有的解析公式都應只關心自己左右兩個表示式的結果
- public SymbolExpression(Expression _left, Expression _right) {
- this.left = _left;
- this.right = _right;
- }
- }
- public class AddExpression extends SymbolExpression {
- public AddExpression(Expression _left, Expression _right) {
- super(_left, _right);
- }
- // 把左右兩個表示式運算的結果加起來
- public int interpreter(HashMap<String, Integer> var) {
- return super.left.interpreter(var) + super.right.interpreter(var);
- }
- }
- public class SubExpression extends SymbolExpression {
- public SubExpression(Expression _left, Expression _right) {
- super(_left, _right);
- }
- // 解析就是減法運算
- public int interpreter(HashMap<String, Integer> var) {
- return super.left.interpreter(var) - super.right.interpreter(var);
- }
- }
- public class Calculator {
- // 定義的表示式
- private Expression expression;
- // 建構函式傳參,並解析
- public Calculator(String expStr) {
- // 定義一個堆疊,安排運算的先後順序
- Stack<Expression> stack = new Stack<Expression>();
- // 表示式拆分為字元陣列
- 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();
- 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])));
- }
- }
- // 把運算結果丟擲來
- this.expression = stack.pop();
- }
- // 開始運算
- public int run(HashMap<String, Integer> var) {
- return this.expression.interpreter(var);
- }
- }
- public class Client {
- // 執行四則運算
- public static void main(String[] args) throws IOException {
- String expStr = getExpStr();
- // 賦值
- HashMap<String, Integer> var = getValue(expStr);
- Calculator cal = new Calculator(expStr);
- System.out.println("運算結果為:" + expStr + "=" + cal.run(var));
- }
- // 獲得表示式
- public static String getExpStr() throws IOException {
- System.out.print("請輸入表示式:");
- return (new BufferedReader(new InputStreamReader(System.in)))
- .readLine();
- }
- // 獲得值對映
- public static HashMap<String, Integer> getValue(String exprStr)
- throws IOException {
- HashMap<String, Integer> map = new HashMap<String, Integer>();
- // 解析有幾個引數要傳遞
- for (char ch : exprStr.toCharArray()) {
- if (ch != '+' && ch != '-') {
- if (!map.containsKey(String.valueOf(ch))) { // 解決重複引數的問題
- System.out.print("請輸入" + ch + "的值:");
- String in = (new BufferedReader(new InputStreamReader(
- System.in))).readLine();
- map.put(String.valueOf(ch), Integer.valueOf(in));
- }
- }
- }
- return map;
- }
- }
轉自:http://blog.csdn.net/yuanlong_zheng/article/details/7584871
相關文章
- 直譯器模式(Interpreter)2019-07-17模式
- Rust語言之GoF設計模式: 直譯器Interpreter模式2022-09-26RustGo設計模式
- PHP設計模式(二十二)—直譯器模式(Interpreter Patt2021-09-09PHP設計模式
- 設計模式之直譯器模式2020-09-22設計模式
- 極簡設計模式-直譯器模式2021-12-10設計模式
- 簡說設計模式——直譯器模式2019-05-28設計模式
- 設計模式--直譯器模式和狀態模式2020-10-27設計模式
- 設計模式(十五)直譯器2023-11-28設計模式
- 23種設計模式之直譯器模式2018-12-27設計模式
- 20.java設計模式之直譯器模式2021-01-20Java設計模式
- 折騰Java設計模式之直譯器模式2019-01-13Java設計模式
- 軟體設計模式系列之十七——直譯器模式2023-09-28設計模式
- 直譯器設計模式知識概括2020-10-13設計模式
- 行為型設計模式2024-06-24設計模式
- (Java)設計模式:行為型2022-11-28Java設計模式
- 設計模式之中介者模式(行為型)2019-04-17設計模式
- 聊一聊設計模式(四)-- 行為型設計模式2020-02-21設計模式
- 設計模式 第十章 備忘錄模式、直譯器模式、狀態模式2020-12-20設計模式
- 行為型設計模式 - 狀態模式詳解2020-05-15設計模式
- 行為型設計模式 - 備忘錄模式詳解2020-05-08設計模式
- 行為型設計模式 - 責任鏈模式詳解2020-05-19設計模式
- 行為型設計模式 - 觀察者模式詳解2020-05-03設計模式
- Java設計模式-17、直譯器模式-自定義語言的實現2020-11-22Java設計模式
- 物件導向-設計模式-行為型2021-07-24物件設計模式
- 大話 PHP 設計模式--行為型2019-10-11PHP設計模式
- 行為型:迭代器模式2023-04-11模式
- 24_直譯器模式2024-03-17模式
- 設計模式學習筆記(二十二)直譯器模式及其實現2022-04-12設計模式筆記
- 設計模式(二十一)——直譯器模式(Spring 框架中SpelExpressionParser原始碼分析)2021-02-10設計模式Spring框架Express原始碼
- 化繁為簡的翻譯機——直譯器模式2019-01-28模式
- 設計模式(二十四)----行為型模式之迭代器模式2023-03-17設計模式
- 行為型設計模式---模板方法觀察者模式責任鏈模式2024-09-02設計模式
- 設計模式-行為型模式-中介者模式2021-09-09設計模式
- 設計模式(十九)----行為型模式之命令模式2023-03-11設計模式
- 初學設計模式(java版)一:行為型模式之--Iterator模式(迭代器模式)2020-12-01設計模式Java
- JavaScript設計模式之建立型設計模式2019-01-02JavaScript設計模式
- 行為型命令模式2024-03-26模式
- vscode如何新增本地python直譯器、解析器 Interpreter?(Python: Select Interpreter),並在vscode執行python程式碼2024-06-03VSCodePython
- 行為型模式:迭代器模式2019-02-28模式