深入淺出基於Java的解譯器設計模式

來源:互聯網
上載者:User
設計 一、引子

  其實沒有什麼好的例子引入解譯器模式,因為它描述了如何構成一個簡單的語言解譯器,主要應用在使用物件導向語言開發編譯器中;在實際應用中,我們可能很少碰到去構造一個語言的文法的情況。

  雖然你幾乎用不到這個模式,但是看一看還是能受到一定的啟發的。

  二、定義與結構

  解譯器模式的定義如下:定義語言的文法,並且建立一個解譯器來解釋該語言中的句子。它屬於類的行為模式。這裡的語言意思是使用規定格式和文法的代碼。

  在GOF的書中指出:如果一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個執行個體表述為一個簡單語言中的句子。這樣就可以構建一個解譯器,該解譯器通過解釋這些句子來解決該問題。而且當文法簡單、效率不是關鍵問題的時候效果最好。

  這也就是解譯器模式應用的環境了。

  讓我們來看看神秘的解譯器模式是由什麼來組成的吧。

  1) 抽象運算式角色:聲明一個抽象的解釋操作,這個介面為所有具體運算式角色(抽象文法樹中的節點)都要實現的。

  什麼叫做抽象文法樹呢?《java與模式》中給的解釋為:抽象文法樹的每一個節點都代表一個語句,而在每個節點上都可以執行解釋方法。這個解釋方法的執行就代表這個語句被解釋。由於每一個語句都代表這個語句被解釋。由於每一個語句都代表一個常見的問題的執行個體,因此每一個節點上的解釋操作都代表對一個問題執行個體的解答。

  2) 終結符運算式角色:具體運算式。

  a) 實現與文法中的終結符相關聯的解釋操作

  b) 而且句子中的每個終結符需要該類的一個執行個體與之對應

  3) 非終結符運算式角色:具體運算式。

  a) 文法中的每條規則R::=R1R2…Rn都需要一個非終結符錶帶式角色

  b) 對於從R1到Rn的每個符號都維護一個抽象運算式角色的執行個體變數

  c) 實現解釋操作,解釋一般要遞迴地調用表示從R1到Rn的那些對象的解釋操作

  4) 上下文(環境)角色:包含解譯器之外的一些全域資訊。

  5) 客戶角色:

  a) 構建(或者被給定)表示該文法定義的語言中的一個特定的句子的抽象文法樹

  b) 調用解釋操作

  放上張解譯器結構類圖吧,這也是來自於GOF的書中。



  對每一個角色都給出了詳細的職責,而且在類圖中給出五個角色之間的關係。這樣實現起來也不是很困難了,下面舉了一個簡單的例子,希望能加深你對解譯器模式的理解。

  三、舉例

  來舉一個加減乘除的例子吧,實現思路來自於《java與模式》中的例子。每個角色的功能按照上面提到的規範來實現。

//上下文(環境)角色,使用HashMap來儲存變數對應的數值

class Context
{
 private Map valueMap = new HashMap();
 public void addValue(Variable x , int y)
 {
  Integer yi = new Integer(y);
  valueMap.put(x , yi);
 }

 public int LookupValue(Variable x)
 {
  int i = ((Integer)valueMap.get(x)).intValue();
  return i ;
 }
}

//抽象運算式角色,也可以用介面來實現

abstract class Expression
{
 public abstract int interpret(Context con);
}

//終結符運算式角色

class Constant extends Expression
{
 private int i ;
 public Constant(int i)
 {
  this.i = i;
 }

 public int interpret(Context con)
 {
  return i ;
 }
}

class Variable extends Expression
{
 public int interpret(Context con)
 {
  //this為調用interpret方法的Variable對象
  return con.LookupValue(this);
 }
}

//非終結符運算式角色

class Add extends Expression
{
 private Expression left ,right ;
 public Add(Expression left , Expression right)
 {
  this.left = left ;
  this.right= right ;
 }

 public int interpret(Context con)
 {
  return left.interpret(con) + right.interpret(con);
 }
}

class Subtract extends Expression
{
 private Expression left , right ;
 public Subtract(Expression left , Expression right)
 {
  this.left = left ;
  this.right= right ;
 }

 public int interpret(Context con)
 {
  return left.interpret(con) - right.interpret(con);
 }

}

class Multiply extends Expression
{
 private Expression left , right ;
 public Multiply(Expression left , Expression right)
 {
  this.left = left ;
  this.right= right ;
 }
 public int interpret(Context con)
 {
  return left.interpret(con) * right.interpret(con);
 }
}

class Division extends Expression
{
 private Expression left , right ;
 public Division(Expression left , Expression right)
 {
  this.left = left ;
  this.right= right ;
 }

 public int interpret(Context con)
 {
  try{
   return left.interpret(con) / right.interpret(con);
  }catch(ArithmeticException ae)
  {
   System.out.println("被除數為0!");
   return -11111;
  }
 }
}

//測試程式,計算 (a*b)/(a-b+2)

public class Test
{
 private static Expression ex ;
 private static Context con ;
 public static void main(String[] args)
 {
  con = new Context();
  //設定變數、常量
  Variable a = new Variable();
  Variable b = new Variable();
  Constant c = new Constant(2);
  //為變數賦值
  con.addValue(a , 5);
  con.addValue(b , 7);
  //運算,對句子的結構由我們自己來分析,構造
  ex = new Division(new Multiply(a , b), new Add(new Subtract(a , b) , c));
  System.out.println("運算結果為:"+ex.interpret(con));
 }
}

  解譯器模式並沒有說明如何建立一個抽象文法樹,因此它的實現可以多種多樣,在上面我們是直接在Test中提供的,當然還有更好、更專業的實現方式。

  對於終結符,GOF建議採用享元模式來共用它們的拷貝,因為它們要多次重複出現。但是考慮到享元模式的使用局限性,我建議還是當你的系統中終結符重複的足夠多的時候再考慮享元模式。

  四、優缺點

  解譯器模式提供了一個簡單的方式來執行文法,而且容易修改或者擴充文法。一般系統中很多類使用相似的文法,可以使用一個解譯器來代替為每一個規則實現一個解譯器。而且在解譯器中不同的規則是由不同的類來實現的,這樣使得添加一個新的文法規則變得簡單。

  但是解譯器模式對於複雜文法難以維護。可以想象一下,每一個規則要對應一個處理類,而且這些類還要遞迴調用抽象運算式角色,多如亂麻的類交織在一起是多麼恐怖的一件事啊!

  五、總結

  這樣對解譯器模式應該有了些大體的認識了吧,由於這個模式使用的案例匱乏,所以本文大部分觀點直接來自於GOF的原著。只是執行個體代碼是親自實現並調試通過的。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.