一、解释器模式概述
解释器模式定义:给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。(类行为型)
- 解释器模式的优缺点:
- 优点:
- 1.将每一个语法规则表示成一个类,方便于实现语言;
- 2.因为语法由许多类表示,所以你可以轻易地改变或扩展此语言;
- 3.通过在类结构中加入新的方法,可以在解释的同时增加新的行为,例如打印格式的美化或者进行复杂的程序验证。
- 缺点:
- 当语法规则的数目太大时,这个模式可能会变得非常繁杂。在这种情况下,使用解析器/编译器的产生器可能更合适。
- 优点:
- 适用场景:
- 1.当你需要实现一个简单的语言时,使用解释器;
- 2.当你有一个简单的语法,而且简单比效率更重要时,使用解释器;
- 3.可以处理脚本语言和编程语言。
解释器模式与适配器模式这两个模式类似 , 但是略有不同:
- 适配器模式 : 不需要预先知道适配器的规则;
- 解释器模式 : 需要预先将规则写好 , 根据规则执行解释。
二、代码实现
解释器模式主要角色如下:
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
用解释器模式设计一个“韶粵通”公交车卡的读卡器程序。
说明:假如“韶粵通”公交车读卡器可以判断乘客的身份,如果是“韶关”或者“广州”的“老人” “妇女”“儿童”就可以免费乘车,其他人员乘车一次扣 2 元。
文法规则如下: <expression> ::= <city>的<person> <city> ::= 韶关|广州 <person> ::= 老人|妇女|儿童
2.1 抽象表达式(IExpression)
package interpreter.buscard;
//抽象表达式类
public interface IExpression{
public boolean interpret(String info);
}
2.2 终结符表达式(TerminalExp)
package interpreter.buscard;
import java.util.HashSet;
import java.util.Set;
//终结符表达式类
public class TerminalExp implements IExpression {
private Set<String> set = new HashSet<>();
public TerminalExp(String[] data) {
for (int i = 0; i < data.length; i++){
set.add(data[i]);
}
}
@Override
public boolean interpret(String info) {
// TODO Auto-generated method stub
if (set.contains(info)){
return true;
}
return false;
}
}
2.3 非终结符表达式(AndExpression)
package interpreter.buscard;
//非终结符表达式类
public class AndExpression implements IExpression {
private IExpression city = null;
private IExpression person = null;
public AndExpression(IExpression city, IExpression person) {
this.city = city;
this.person = person;
}
@Override
public boolean interpret(String info) {
// TODO Auto-generated method stub
String[] s = info.split("的");
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
2.4 环境(context)
package interpreter.buscard;
//环境类
public class Context {
private String[] cities = {"韶关","广州"};
private String[] persons = {"老人","妇女","儿童"};
private IExpression cityPerson;
public Context() {
IExpression city = new TerminalExp(cities);
IExpression person = new TerminalExp(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元!");
}
}
}
2.5 客户端(Test)
package interpreter.buscard;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Context bus = new Context();
bus.freeRide("韶关的老人");
bus.freeRide("韶关的年轻人");
bus.freeRide("广州的妇女");
bus.freeRide("广州的儿童");
bus.freeRide("山东的儿童");
}
}