首頁>資訊>

簡介

今天給大家介紹的設計模式叫做“直譯器模式”,該模式是“行為型設計模式”中的一員。

直譯器模式的核心思想是:給定一個語言,定義它的文法的一種表示,並定義一個直譯器,使用該直譯器來解釋語言中的句子。

聽完這句話話是不是頓時感覺一臉懵?什麼語言、文法、句子,都是些什麼鬼?

別慌讓“菜鳥”來給你分析一波。

文法:可以將其理解為一種規則,就好比漢語中一句話必須由“主謂賓”三者構成一樣。句子:符合文法規則的一種表現,可以簡單理解成符合漢語規則的一句話。語言:將所有句子彙集起來的一個集合就是語言。

我們可以透過直譯器將語言中的句子解析成一顆語法樹,從而對其進行操作。所謂的語法樹就是將句子透過文法進行推導,進而獲取到句子的一顆樹形表現形式。

直譯器模式UML類圖

類圖講解

Context:環境角色(上下文),含有每個直譯器所需的一些資料或全域性的一些資訊。AbstractExpression:抽象表示式類,聲明瞭抽象的解釋操作,所有直譯器類都繼承或實現該類。TerminalExpression:終結符表示式類,是AbstractExpression的子類,實現了文法中有關終結符相關的解釋操作。TerminalExpression:非終結符表示式,AbstractExpression的子類,該類的功能與終結表示式類相反,文法中所有非終結符由該類進行解釋。Client:客戶端測試類。

案例講解

下面讓我們透過一個經典的“計算器”案例來詳細瞭解一下直譯器模式。

注:本文重點講解的是直譯器模式故示例程式碼只實現了加減法的運算。

表示式介面

public interface Expression {  /**   * 解釋表示式的抽象方法   *   * @param map 比如現有表示式:a + b;那麼map中存放的就是{a=10,b=20}   * @return 返回解釋後的值。   */  int interpreter(Map<String, Integer> map);}

變數解析器類

public class VarExpression implements Expression {  // 公式中的變數。  private String key;  public VarExpression(String key) {    this.key = key;  }  // 透過key獲取所對應的值  @Override  public int interpreter(Map<String, Integer> map) {    return map.get(key);  }}

運算子解析器類

public class SymbolExpression implements Expression {  /**   * 假如現有表示式:a + b - c 需要解析。   * 分析:   *  1、一個運算子連線的是它左右兩個數字。   *  2、如上表達式【+】號連線的是吧“a"和"b",【-】號連線的是"a + b"和“c”。   *  3、經次分析我們將運算子連線的左右都看成是一個表示式也就是Expression。   */  // 左表示式  protected Expression leftExpression;  // 右表示式  protected Expression rightExpression;  public SymbolExpression(Expression leftExpression, Expression rightExpression) {    this.leftExpression = leftExpression;    this.rightExpression = rightExpression;  }  // 不同種類的運算子由不同的運算子子類進行解析,所以該類不實現interpreter方法。  @Override  public int interpreter(Map<String, Integer> map) {    return 0;  }}

減法解析器

public class SubExpression extends SymbolExpression {  public SubExpression(Expression leftExpression, Expression rightExpression) {    super(leftExpression, rightExpression);  }  // 解釋減法  @Override  public int interpreter(Map<String, Integer> map) {    return leftExpression.interpreter(map) - rightExpression.interpreter(map);  }}

加法解析器

public class AddExpression extends SymbolExpression {  public AddExpression(Expression leftExpression, Expression rightExpression) {    super(leftExpression, rightExpression);  }  // 解釋加法  @Override  public int interpreter(Map<String, Integer> map) {    return leftExpression.interpreter(map) + rightExpression.interpreter(map);  }}

計算器 => 對應Context角色

public class Calculator {  // 表示式  private Expression expression;  public Calculator(String strExpression) {    char[] charArray = strExpression.toCharArray();    // 定義棧用於儲存表示式,因示例簡單故不考慮運算順序。    Stack<Expression> stack = new Stack<>();    Expression left;    Expression right;    // 解析表示式    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])));          break;      }    }    // 遍歷完成獲取最終解析好的表示式。    this.expression = stack.pop();  }  /**   *   * @param map 表示式對應的值   * @return 計算的結果   */  public int calculate(Map<String, Integer> map) {    return this.expression.interpreter(map);  }}

客戶端測試類

public class Client {  public static void main(String[] args) {    // 表示式    String strExpression = "a+b-c+d";    // 表示式對應的值    Map<String, Integer> map = new HashMap<>();    map.put("a", 2);    map.put("b", 10);    map.put("c", 8);    map.put("d", 13);    // 建立計算器    Calculator calculator = new Calculator(strExpression);    // 計算    int result = calculator.calculate(map);    System.out.println("表示式:" + strExpression + "的計算結果為:" + result);  }}

執行結果

總結

1、使用直譯器模式可以提高程式碼的可擴充套件性。

2、使用直譯器模式會引起類膨脹。

3、直譯器模式會採用遞迴呼叫方法,可能會降低效率,並且會提高維護和除錯的成本。

4、直譯器模式的使用場景比較少,開發中也不經常接觸到,一般常用在編譯器、運算表示式計算、正則表示式解析等。

21
最新評論
  • 購得日本70萬平方公尺小島的中國女子是誰?
  • 被神撿到的男人?幸運嗎?