Interpreter Expression 解釋器模式 [MD]


博文地址

我的GitHub 我的博客 我的微信 我的郵箱
baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

解釋器模式

簡介

Interpreter模式也叫解釋器模式,是行為模式之一,它是一種特殊的設計模式,它建立一個解釋器,對於特定的計算機程序設計語言,用來解釋預先定義的文法

應用環境:

  • 如果一種特定類型的問題發生的頻率足夠高,那么可能就值得將該問題的各個實例表述為一個簡單語言中的句子。這樣就可以構建一個解釋器,該解釋器通過解釋這些句子來解決該問題。而且當文法簡單、效率不是關鍵問題的時候效果最好。
  • 當有一個語言需要解釋執行,並且你可將該語言中的句子表示為一個抽象語法樹,可以使用解釋器模式。

角色:

  • 抽象表達式角色(AbstractExpression): 聲明一個抽象的解釋操作,這個接口為所有具體表達式角色都要實現的
  • 終結符表達式角色(TerminalExpression): 實現與文法中的元素相關聯的解釋操作,通常一個解釋器模式中只有一個終結符表達式,但有多個實例對應不同的終結符
  • 非終結符表達式角色(NonterminalExpression): 文法中的每條規則對應於一個非終結表達式,非終結表達式根據邏輯的復雜程度而增加,原則上每個文法規則都對應一個非終結符表達式
  • 環境角色(Context): 包含解釋器之外的一些全局信息

優點:

  • 解釋器是一個簡單語法分析工具,它最顯著的優點就是【擴展性】,修改語法規則只要修改相應的【非終結符表達式】就可以了,若擴展語法,則只要增加【非終結符類】就可以了。

缺點:

  • 解釋器模式會引起【類膨脹】,每個語法都要產生一個非終結符表達式,語法規則比較復雜時,可能產生大量的類文件,難以維護
  • 解釋器模式采用【遞歸調用】方法,它導致調試非常復雜
  • 解釋器由於使用了大量的循環和遞歸,所以當用於解析復雜、冗長的語法時,【效率】是難以忍受的

注意事項:

盡量不要在重要模塊中使用解釋器模式,因為維護困難。在項目中,可以使用shell,JRuby,Groovy等腳本語言來代替解釋器模式

作用:用一組類代表某一規則

這個模式通常定義了一個語言的語法,然后解析相應語法的語句。

java.util.Pattern
java.text.Format

案例一

環境角色

class Context {
    private Map<String, Integer> valueMap = new HashMap<String, Integer>();
    public void addValue(String key, int value) {
        valueMap.put(key, value);
    }
    public int getValue(String key) {
        return valueMap.get(key);
    }
}

抽象表達式角色

聲明一個抽象的解釋操作,這個接口為所有具體表達式角色都要實現的

abstract class AbstractExpression {
    public abstract int interpreter(Context context);
}

終結符表達式角色

實現與文法中的元素相關聯的解釋操作,通常一個解釋器模式中只有一個終結符表達式,但有多個實例對應不同的終結符 
Terminal 終結符,末期的,晚期的。終結符是語言中用到的基本元素,一般不能再被分解

class TerminalExpression extends AbstractExpression {
    private int i;
    public TerminalExpression(int i) {
        this.i = i;
    }
    @Override
    public int interpreter(Context context) {//不進行任何操作
        return i;
    }
}

非終結符表達式角色

文法中的每條規則對應於一個非終結表達式,非終結表達式根據邏輯的復雜程度而增加

加法操作

class AddNTExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;
    public AddNTExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
    @Override
    public int interpreter(Context context) {
        return left.interpreter(context) + right.interpreter(context);
    }
}

減法操作

class SubtractNTExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;
    public SubtractNTExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
    @Override
    public int interpreter(Context context) {
        return left.interpreter(context) - right.interpreter(context);
    }
}

乘法操作

class MultiplyNTExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;
    public MultiplyNTExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
    @Override
    public int interpreter(Context context) {
        return left.interpreter(context) * right.interpreter(context);
    }
}

除法操作

class DivisionNTExpression extends AbstractExpression {
    private AbstractExpression left;
    private AbstractExpression right;
    public DivisionNTExpression(AbstractExpression left, AbstractExpression right) {
        this.left = left;
        this.right = right;
    }
    @Override
    public int interpreter(Context context) {
        int value = right.interpreter(context);
        if (value != 0) return left.interpreter(context) / value;
        return -1111;
    }
}

使用演示

public class Test {
    public static void main(String[] args) {
        //計算(7*8)/(7-8+2)的值
        Context context = new Context();
        context.addValue("a", 7);
        context.addValue("b", 8);
        context.addValue("c", 2);

        AbstractExpression multiplyValue = new MultiplyNTExpression(new TerminalExpression(context.getValue("a")), new TerminalExpression(context.getValue("b")));//計算a*b
        AbstractExpression subtractValue = new SubtractNTExpression(new TerminalExpression(context.getValue("a")), new TerminalExpression(context.getValue("b")));//計算a-b

        AbstractExpression addValue = new AddNTExpression(subtractValue, new TerminalExpression(context.getValue("c")));//計算(a-b)+c

        AbstractExpression divisionValue = new DivisionNTExpression(multiplyValue, addValue);//計算(a*b)/(a-b+c)

        System.out.println(divisionValue.interpreter(context));
    }
}

案例二

創建一個表達式接口

public interface Expression { //表達式接口
   boolean interpret(String context); //解釋指定的內容
}

創建實現了上述接口的實體類

public class TerminalExpression implements Expression {
   private String data;
   public TerminalExpression(String data){
      this.data = data;
   }
   @Override
   public boolean interpret(String context) {
      if(context.contains(data)){ //包含
         return true;
      }
      return false;
   }
}
public class OrExpression implements Expression {

   private Expression expr1 = null;
   private Expression expr2 = null;

   public OrExpression(Expression expr1, Expression expr2) {
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {
      return expr1.interpret(context) || expr2.interpret(context); //兩個表達式是否有一個能解釋指定內容
   }
}
public class AndExpression implements Expression {

   private Expression expr1 = null;
   private Expression expr2 = null;

   public AndExpression(Expression expr1, Expression expr2) {
      this.expr1 = expr1;
      this.expr2 = expr2;
   }

   @Override
   public boolean interpret(String context) {
      return expr1.interpret(context) && expr2.interpret(context); //兩個表達式是否都能解釋指定內容
   }
}

測試

public class Test {
    public static void main(String[] args) {
        //使用 Expression 類來創建規則,並解析它們。
        Expression robert = new TerminalExpression("Robert");
        Expression john = new TerminalExpression("John");
        Expression or = new OrExpression(robert, john);
        System.out.println(or.interpret("John")); //true

        Expression julie = new TerminalExpression("Julie");
        Expression married = new TerminalExpression("Married");
        Expression and = new AndExpression(julie, married);
        System.out.println(and.interpret("Married Julie")); //true
    }
}

2016-08-24


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM