本文已参与[新人创作礼]活动,一起开启掘金创作之路
1. 概念
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解释器来解释语言中的句子.也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。 是一种类行为型模式。
2. 优点
- 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 容易实现。在语法树中的每个表达式节点都是相似的,所以实现其文法较为容易。
3. 缺点
- 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较为复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
- 会引起类膨胀。解释器模式中的每条规则至少许哟啊定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
- 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
4. 结构与实现
4.1 结构
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
4.2 实现
//环境类
public class Context {
private String[] citys = {"韶关", "广州"};
private String[] persons = {"老人", "妇女", "儿童"};
private Expression noTerminalExpression;
//数据初始化
public Context(){
Expression city = new TerminalExpression(citys);
Expression person = new TerminalExpression(persons);
noTerminalExpression = new NoTerminalExpression(city,person);
}
public void operation(String info) {
boolean ok = noTerminalExpression.interpret(info);
if (ok) System.out.println("您是" + info + ",您本次乘车免费!");
else System.out.println(info + ",您不是免费人员,本次乘车扣费2元!");
}
}
//抽象表达式角色
public interface Expression {
boolean interpret(String info);
}
//非终结表达式类
public class NoTerminalExpression implements Expression {
private Expression city;
private Expression person;
public NoTerminalExpression(Expression city, Expression person) {
this.city = city;
this.person = person;
}
@Override
public boolean interpret(String info) {
String s[] = info.split("的");
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
//终结表达式类
public class TerminalExpression implements Expression{
private Set<String> citys = new HashSet<>();
public TerminalExpression(String[] data) {
for (String s :
data) {
citys.add(s);
}
}
@Override
public boolean interpret(String info) {
return citys.contains(info);
}
}
测试
public class ExpressionTest {
@Test
public void test1(){
Context bus = new Context();
bus.operation("韶关的老人");
bus.operation("韶关的年轻人");
bus.operation("广州的妇女");
bus.operation("广州的儿童");
bus.operation("山东的儿童");
}
}