此次介紹另外一個行爲模式,解釋器模式,都說解釋器模式用的少,其實只是咱們在平常的開發中用的少,可是一些開源框架中仍是能見到它的影子,例如:spring的spEL表達式在解析時就用到了解釋器模式,以及mybatis在將SQL語句映射成對象時關係時、還有一些解析正則表達式和解析json等開源工具。html
解釋器模式是指給定一個使用規定格式和語法的語言,而且創建一個解釋器來解釋該語言中的句子。解釋器自己就是一種按照規定的語法進行解析的方案,可是整體來講也是一種使用頻率相對較低但學習難度較大的設計模式。正則表達式
由於解釋器模式用到地方不太多,實在想不到舉什麼樣的例子合適,因此就使用一個簡單的來實現一個壘加的功能的例子吧。spring
具體過程以下:json
上下文環境類設計模式
@Getter @Setter public class Context { /** * 輸入 */ private String input; /** * 結果 */ private int output; public Context(String input){ this.input = input; } @Override public String toString() { return input + "=" + output; } }
抽象表達式類mybatis
public abstract class Expression { Context context; /** * 解釋一個給定的表達式 * @param context */ public abstract void interpret(Context context); }
壘加類框架
/** * 壘加1 */ public class MinusExpression extends Expression { /** * 解釋一個給定的表達式 * * @param context */ @Override public void interpret(Context context) { this.context = context; String input = context.getInput(); int in = Integer.valueOf(input); context.setOutput(in-1); } @Override public String toString() { return "--"+context.getInput()+"="+context.getOutput(); } }
壘減ide
/** * 壘減 */ public class PlusExpression extends Expression { /** * 解釋一個給定的表達式 * * @param context */ @Override public void interpret(Context context) { this.context = context; String input = context.getInput(); int in = Integer.valueOf(input); context.setOutput(in+1); } @Override public String toString() { return "++"+context.getInput()+"="+context.getOutput(); } }
測試,使用工具
public class Client { public static void main(String[] args) { Context context = new Context("50"); Expression plus = new PlusExpression(); Expression minus = new MinusExpression(); //執行壘加 plus.interpret(context); System.out.println(plus.toString()); //壘減 minus.interpret(context); System.out.println(minus.toString()); } }
運行結果post
++50=51 --50=49
經過運算結果能夠看出來,表達式經過解釋後的結果,++50解釋後結果是51,--50解釋後結果是49。
解釋器模式的結構圖以下:
解釋器類圖上的各個角色說明:
Expression(抽象解釋器):定義解釋方法,具體的解釋任務由各個實現類完成,具體的解釋器分別由TerminalRxpression和NonterMinalExpression完成。抽象解釋器對應上面例子中的Expression類
TerminalExpression(終結符表達式):實現與文法中的元素相關的解釋操做,一個解釋器模式中只有一個終結符表達式,但有多個實例,對應不一樣的終結符。上面的代碼例子中的PlusExpression和MinusExpression都是這個角色。
NoteTerminalExpression(非終結符表達式):文法中的每條規則對應於一個非終結符表達式。非終結符表達式是根據邏輯的複雜度而增長,原則上每一個文法規則都對應一個非終結符表達式。因爲上面舉得例子比較簡單,因此上面的例子中是沒有這個角色的。
Context(環境角色):環境類又稱爲上下文類,它用於存儲解釋器以外的一些全局信息,一般它臨時存儲了須要解釋的語句。也可使用集合用來存儲要解釋的內容。
一、易於改變和擴展文法。由於該模式使用類表示文法,因此可使用繼承改變或擴展該文法。
二、每條文法規則均可以是一個類,因此能夠很方便的實現一個簡單的語言。
三、易於實現文法的定義。在抽象語法樹中每個表達式節點類的實現方式都是類似的,這些類的代碼編寫都不會特別複雜,還能夠經過一些工具自動生成節點類代碼。
四、增長新的解釋表達式較爲方便。若是用戶須要增長新的解釋表達式只須要對應增長一個新的終結符表達式或非終結符表達式類,原有表達式類代碼無須修改,符合「開閉原則」。
一、對於複雜文法難以維護。在解釋器模式中,每一條規則至少須要定義一個類,所以若是一個語言包含太多文法規則,類的個數將會急劇增長,致使系統難以管理和維護,此時能夠考慮使用語法分析程序等方式來取代解釋器模式。
二、執行效率較低。因爲在解釋器模式中使用了大量的循環和遞歸調用,所以在解釋較爲複雜的句子時其速度很慢,並且代碼的調試過程也比較麻煩。
一、能夠將一個須要解釋執行的語言中的句子表示爲一個抽象語法樹。
三、一個語言的文法較爲簡單。
四、執行效率不是關鍵問題。【注:高效的解釋器一般不是經過直接解釋抽象語法樹來實現的,而是須要將它們轉換成其餘形式,使用解釋器模式的執行效率並不高。】
想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。