# It can explain what ? 如下是解釋器要解釋的主體: - 加減乘除等運算,3+4/9+6*8 - 摩爾斯電碼 - 正則表達式 - El表達式 - OGNL表達式 - 小明是北京人 - 小紅是一名售貨員 - 部門領導下發一則通知 - ... # How explain ? 解釋器 ...
It can explain what ?
如下是解釋器要解釋的主體:
- 加減乘除等運算,3+4/9+6*8
- 摩爾斯電碼
- 正則表達式
- El表達式
- OGNL表達式
- 小明是北京人
- 小紅是一名售貨員
- 部門領導下發一則通知
- ...
How explain ?
解釋器模式常用於對簡單語言集的編譯或分析,例如:
- 我是大學生
- 張強學習編程
- 小明是北京人
- 部門領導下發一則通知
為了掌握好它的結構與實現,需要先瞭解編譯原理中的文法
、句子
、語法樹
等相關概念。(其實不瞭解也行,可以直接看code,在回來看)
這裡提到的文法和句子的概念同編譯原理
中的描述相同,
文法
指語言的語法規則
如何解釋語言的規則句子
是語言集中的元素
例如,漢語中的句子有很多,“我是大學生”是其中的一個句子,可以用一棵語法樹來直觀地描述語言中的句子。
Grammar Concept
這個是分析的關鍵。
〈句子〉::=〈主語〉〈謂語〉〈賓語〉
〈主語〉::=〈代詞〉|〈名詞〉
〈謂語〉::=〈動詞〉
〈賓語〉::=〈代詞〉|〈名詞〉
〈代詞〉::= 你 | 我 | 他
〈名詞〉::= 大學生 | 小明 | 英語 | 張強
〈動詞〉::= 是 | 學習
註意:
::=
表示“定義為”的意思;- 用
〈
和〉
括住的是非終結符
, 沒有括住的是終結符
; - | 是 邏輯符號or.
Sentence
句子是語言的基本單位,是語言集中的一個元素,它由終結符構成,能由"文法"推導出。
例如,上述文法可以推出“我是大學生”,所以它是句子。
Syntax Tree
語法樹是句子結構的一種樹型表示,它代表了句子的推導結果,它有利於理解句子語法結構的層次。
“我是大學生”的語法樹如圖所示:
<expression> ::= <代詞>是<名詞>
<代詞> ::= 我 | 你 | 他 | 她
<名詞> ::= 大學生 | 程式員 | 牲口 | 懦夫
終結符和非終結符
終結符表達式
(Terminal Expression):
就是一個最終的元素,不可在向下分割。
非終結符表達式
(Nonterminal Expression):
非終結符需要依照文法規則去分割,文法中的每條規則都對應於一個非終結符表達式。
Key Elements
解釋器模式包含以下主要角色。
- 抽象表達式(Abstract Expression)角色:定義解釋器的介面,約定解釋器的解釋操作,主要包含解釋方法 interpret()。
- 終結符表達式(Terminal Expression)角色:是抽象表達式的子類,用來實現文法中與終結符相關的操作,文法中的每一個終結符都有一個具體終結表達式與之相對應。
- 非終結符表達式(Nonterminal Expression)角色:也是抽象表達式的子類,用來實現文法中與非終結符相關的操作,文法中的每條規則都對應於一個非終結符表達式。
- 環境(Context)角色:通常包含各個解釋器需要的數據或是公共的功能,一般用來傳遞被所有解釋器共用的數據,後面的解釋器可以從這裡獲取這些值。
- 客戶端(Client):主要任務是將需要分析的句子或表達式轉換成使用解釋器對象描述的抽象語法樹,然後調用解釋器的解釋方法,當然也可以通過環境角色間接訪問解釋器的解釋方法。
Example —— 公交車身份識別系統
需求描述:每個人坐車都需要繳費,每個人上車後需要刷自己的公交卡卡,每個人的卡裡都有每個人的信息,信息如下:
- "韶關的老人";
- "韶關的年輕人";
- "廣州的婦女";
- "廣州的兒童";
- "山東的兒童";
你需要寫一個解釋器去識別每個人的身份,如果是“韶關”或者“廣州”的“老人” “婦女”“兒童”就可以免費乘車,其他人員乘車一次扣 2 元。
分析:本實例用“解釋器模式”設計比較適合,首先設計其文法規則如下:
<expression> ::= <city>的<person>
<city> ::= 韶關 | 廣州
<person> ::= 老人 | 婦女 | 兒童
Client
public static void main(String[] args){
Context bus=new Context();
bus.freeRide("韶關的老人");
bus.freeRide("韶關的年輕人");
bus.freeRide("廣州的婦女");
bus.freeRide("廣州的兒童");
bus.freeRide("山東的兒童");
}
Context
class Context {
private String[] citys = {"韶關", "廣州"};
private String[] persons = {"老人", "婦女", "兒童"};
private Expression cityPerson;
public Context() {
Expression city = new TerminalExpression(citys);
Expression person = new TerminalExpression(persons);
cityPerson = new AndExpression(city, person);
}
public void freeRide(String info) {
boolean ok = cityPerson.interpret(info);
if (ok) System.out.println("您是" + info + ",您本次乘車免費!");
else System.out.println(info + ",您不是免費人員,本次乘車扣費2元!");
}
}
//抽象表達式類
interface Expression {
public boolean interpret(String info);
}
//終結符表達式類
class TerminalExpression implements Expression {
private Set<String> set = new HashSet<String>();
public TerminalExpression(String[] data) {
for (int i = 0; i < data.length; i++) set.add(data[i]);
}
public boolean interpret(String info) {
if (set.contains(info))
return true;
return false;
}
}
//非終結符表達式類
class AndExpression implements Expression {
private Expression city = null;
private Expression person = null;
public AndExpression(Expression city, Expression person) {
this.city = city;
this.person = person;
}
public boolean interpret(String info) {
String s[] = info.split("的");
System.out.println(city.interpret(s[0]) && person.interpret(s[1]));
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
out:
true
您是韶關的老人,您本次乘車免費!
false
韶關的年輕人,您不是免費人員,本次乘車扣費2元!
true
您是廣州的婦女,您本次乘車免費!
true
您是廣州的兒童,您本次乘車免費!
false
山東的兒童,您不是免費人員,本次乘車扣費2元!
Reference
設計模式之解釋器模式(Interpreter)詳解及代碼示例
https://www.cnblogs.com/jing99/p/12610089.html