解釋器模式
解釋器模式是類的行為模式署辉。給定一個(gè)語(yǔ)言之后窍仰,解釋器模式可以定義出其文法的一種表示,并同時(shí)提供一個(gè)解釋器导匣〔挪ぃ客戶端可以使用這個(gè)解釋器來(lái)解釋這個(gè)語(yǔ)言中的句子。
意圖 給定一個(gè)語(yǔ)言贡定,定義它的文法表示赋访,并定義一個(gè)解釋器,這個(gè)解釋器使用該標(biāo)識(shí)來(lái)解釋語(yǔ)言中的句子缓待。
主要解決 對(duì)于一些固定文法構(gòu)建一個(gè)解釋句子的解釋器蚓耽。
何時(shí)使用 如果一種特定類型的問(wèn)題發(fā)生的頻率足夠高,那么可能就值得將該問(wèn)題的各個(gè)實(shí)例表述為一個(gè)簡(jiǎn)單語(yǔ)言中的句子旋炒。這樣就可以構(gòu)建一個(gè)解釋器步悠,該解釋器通過(guò)解釋這些句子來(lái)解決該問(wèn)題。
如何解決 構(gòu)件語(yǔ)法樹(shù)瘫镇,定義終結(jié)符與非終結(jié)符鼎兽。
關(guān)鍵代碼 構(gòu)件環(huán)境類,包含解釋器之外的一些全局信息铣除,一般是 HashMap谚咬。
解釋器模式相關(guān)UML圖
類圖
可以看出右側(cè)的協(xié)作圖(object collaboration diagram)展現(xiàn)出運(yùn)行時(shí)的解釋器模式。Client向右側(cè)抽象語(yǔ)法樹(shù)發(fā)送解釋請(qǐng)求尚粘,請(qǐng)求被轉(zhuǎn)發(fā)并向下到樹(shù)結(jié)構(gòu)的所有對(duì)象择卦。
解釋器模式的主要角色
抽象解釋器(AbstractExpression/Expression):聲明一個(gè)所有具體表達(dá)式都要實(shí)現(xiàn)的抽象接口(或者抽象類),接口中主要是一個(gè)interpret()方法背苦,稱為解釋操作互捌。具體解釋任務(wù)由它的各個(gè)實(shí)現(xiàn)類來(lái)完成,具體的解釋器分別由終結(jié)符解釋器TerminalExpression和非終結(jié)符解釋器NonterminalExpression完成行剂。
終結(jié)符表達(dá)式(TerminalExpression):實(shí)現(xiàn)與文法中的元素相關(guān)聯(lián)的解釋操作秕噪,通常一個(gè)解釋器模式中只有一個(gè)終結(jié)符表達(dá)式,但有多個(gè)實(shí)例厚宰,對(duì)應(yīng)不同的終結(jié)符腌巾。終結(jié)符一半是文法中的運(yùn)算單元,比如有一個(gè)簡(jiǎn)單的公式R=R1+R2铲觉,在里面R1和R2就是終結(jié)符澈蝙,對(duì)應(yīng)的解析R1和R2的解釋器就是終結(jié)符表達(dá)式。
非終結(jié)符表達(dá)式(NonterminalExpression):文法中的每條規(guī)則對(duì)應(yīng)于一個(gè)非終結(jié)符表達(dá)式撵幽,非終結(jié)符表達(dá)式一般是文法中的運(yùn)算符或者其他關(guān)鍵字灯荧,比如公式R=R1+R2中,+就是非終結(jié)符盐杂,解析+的解釋器就是一個(gè)非終結(jié)符表達(dá)式逗载。非終結(jié)符表達(dá)式根據(jù)邏輯的復(fù)雜程度而增加哆窿,原則上每個(gè)文法規(guī)則都對(duì)應(yīng)一個(gè)非終結(jié)符表達(dá)式。
環(huán)境角色(Context):這個(gè)角色的任務(wù)一般是用來(lái)存放文法中各個(gè)終結(jié)符所對(duì)應(yīng)的具體值厉斟,比如R=R1+R2挚躯,我們給R1賦值100,給R2賦值200擦秽。這些信息需要存放到環(huán)境角色中码荔,很多情況下我們使用Map來(lái)充當(dāng)環(huán)境角色就足夠了。
干貨代碼
簡(jiǎn)單的一個(gè)解釋器計(jì)算加減乘除算法感挥,環(huán)境上下文沒(méi)有用好缩搅,其實(shí)計(jì)算規(guī)則更多的是人為設(shè)定的了。
本次的抽象接收器用的是抽象類链快,用接口代替也可以誉己。
//抽象解釋器
public abstract class AbstractExpression {
public abstract int interpreter(Context context);
}
//非終結(jié)表達(dá)式:加法
@Data
@AllArgsConstructor
public class Add extends AbstractExpression {
private final AbstractExpression left;
private final AbstractExpression right;
@Override
public int interpreter(Context context) {
return left.interpreter(context) + right.interpreter(context);
}
}
//非終結(jié)表達(dá)式:減法
@Data
@AllArgsConstructor
public class Subtract extends AbstractExpression {
private final AbstractExpression left;
private final AbstractExpression right;
@Override
public int interpreter(Context context) {
return left.interpreter(context) - right.interpreter(context);
}
}
//非終結(jié)表達(dá)式:乘法
@Data
@AllArgsConstructor
public class Multiply extends AbstractExpression {
private final AbstractExpression left;
private final AbstractExpression right;
@Override
public int interpreter(Context context) {
return left.interpreter(context) * right.interpreter(context);
}
}
//非終結(jié)表達(dá)式:除法
@Data
@AllArgsConstructor
public class Division extends AbstractExpression {
private final AbstractExpression left;
private final AbstractExpression right;
@Override
public int interpreter(Context context) {
int right = this.right.interpreter(context);
if (right != 0) {
return left.interpreter(context) / right;
}
return -1;
}
}
//終結(jié)表達(dá)式:變量
@Data
@AllArgsConstructor
public class Variable extends AbstractExpression {
private final String key;
@Override
public int interpreter(Context context) {
return context.getValue(key);
}
}
//環(huán)境上下文
@Getter
public class Context {
private final Map<String, Integer> valueMap = Maps.newHashMap();
public void addValue(final String key, final int value) {
valueMap.put(key, Integer.valueOf(value));
}
public int getValue(final String key) {
return valueMap.get(key).intValue();
}
}
//
public class Application {
public static void main(String[] args) {
Context context = new Context();
context.addValue("a", 6);
context.addValue("b", 9);
context.addValue("c", 1);
Variable a = new Variable("a”);
Variable b = new Variable("b”);
Variable c = new Variable("c”);
AbstractExpression multiplyValue = new Multiply(a, b);
AbstractExpression subtractValue = new Subtract(a, b);
AbstractExpression addValue = new Add(subtractValue, c);
AbstractExpression divisionValue = new Division(multiplyValue, addValue);
log.info("{}", context.getValueMap());
log.info("(a*b)/(a-b+c) = {}", divisionValue.interpreter(context));
}
}
結(jié)果如下:
Java中的應(yīng)用
java中的表達(dá)式引擎
Java表達(dá)式引擎fel/groovy/expression4j/java腳本引擎的性能對(duì)比
JDK中的應(yīng)用
這個(gè)模式通常定義了一個(gè)語(yǔ)言的語(yǔ)法,然后解析相應(yīng)語(yǔ)法的語(yǔ)句域蜗。
java.util.Pattern
java.text.Normalizer
java.text.Format