| 我的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
