一、模式簡介
定義:給分析對象定義一個語言,并定義該語言的文法表示,再設計一個解析器來解釋語言中的句子,用編譯語言的方式來分析應用中的實例。
場景:一個語言需要解釋執行,并且語言中的句子可以表示為一個抽象語法樹的時候。
- 角色結構:
- 抽象表達式(Abstract Expression)角色:定義解釋器的接口,約定解釋器的解釋操作。
- 終結符表達式(Terminal Expression)角色:是抽象表達式的子類,用來實現文法中與終結符相關的操作,文法中的每一個終結符都有一個具體終結表達式與之相對應。
- 非終結符表達式(Nonterminal Expression)角色:也是抽象表達式的子類,用來實現文法中與非終結符相關的操作,文法中的每條規則都對應于一個非終結符表達式。
- 環境(Context)角色:通常包含各個解釋器需要的數據或是公共的功能,一般用來傳遞被所有解釋器共享的數據,后面的解釋器可以從這里獲取這些值。
- 客戶端(Client):主要任務是將需要分析的句子或表達式轉換成使用解釋器對象描述的抽象語法樹,然后調用解釋器的解釋方法,當然也可以通過環境角色間接訪問解釋器的解釋方法。
二、模式實現
public interface AbstractExpression { -> 抽象表達式
boolean interpret(String info);
}
public class TerminalExpression implements AbstractExpression { -> 終結表達式
private Set<String> set = new HashSet<>();
public TerminalExpression(String[] array){
set.addAll(Arrays.asList(array));
}
@Override
public boolean interpret(String info) {
return set.contains(info);
}
}
public class AndExpression implements AbstractExpression { -> 非終結表達式
private AbstractExpression city;
private AbstractExpression card;
public AndExpression(AbstractExpression city, AbstractExpression card) {
this.city = city;
this.card = card;
}
@Override
public boolean interpret(String info) {
String[] array = info.split("使用");
if (array.length < 2) return false;
return city.interpret(array[0]) && card.interpret(array[1]);
}
}
public class ContextExpression { -> 環境表達式
private AbstractExpression ZQExpression = new AndExpression(new TerminalExpression(new String[]{"肇慶"}),
new TerminalExpression(new String[]{"嶺南通"}));
private AbstractExpression GZExpression = new AndExpression(new TerminalExpression(new String[]{"廣州"}),
new TerminalExpression(new String[]{"羊城通", "嶺南通"}));
public void interpret(String info) {
if (ZQExpression.interpret(info) || GZExpression.interpret(info)) {
System.out.println(info + ",可行");
} else {
System.out.println(info + ",不可行");
}
}
}
以不同城市使用不同的公交卡乘車為例子,羊城通公交卡只允許在廣州乘車,嶺南通公交卡則可以在肇慶或廣州乘車。
ContextExpression context = new ContextExpression();
context.interpret("肇慶使用羊城通");
context.interpret("肇慶使用嶺南通");
context.interpret("廣州使用羊城通");
context.interpret("廣州使用嶺南通");