1、概念
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
优点:
- 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
- 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。
缺点:
- 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。
- 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。
- 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。
2、实现
解释器模式包含以下主要角色:
- 抽象表达式(Abstract Expression)角色:定义解释器的接口,约定解释器的解释操作,主要包含解释方法 interpret()。
- 终结符表达式(Terminal Expression)角色:是抽象表达式的子类,用来实现文法中与终结符相关的操作,文法中的每一个终结符都有一个具体终结表达式与之相对应。
- 非终结符表达式(Nonterminal Expression)角色:也是抽象表达式的子类,用来实现文法中与非终结符相关的操作,文法中的每条规则都对应于一个非终结符表达式。
- 环境(Context)角色:通常包含各个解释器需要的数据或是公共的功能,一般用来传递被所有解释器共享的数据,后面的解释器可以从这里获取这些值。
- 客户端(Client):主要任务是将需要分析的句子或表达式转换成使用解释器对象描述的抽象语法树,然后调用解释器的解释方法,当然也可以通过环境角色间接访问解释器的解释方法。
下面用解释器模型解决坐地铁免费的问题,假设身高在1.3以下的小孩和年龄65岁以上的老人免费乘车。
package com.mine.design.interpreter;
public class Passenger {
private String name;
private int age;
private int height;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Passenger [name=" + name + ", age=" + age + ", height=" + height + "]";
}
}
package com.mine.design.interpreter;
public interface Expression {
boolean interpret(int info);
}
package com.mine.design.interpreter;
public class TerminalExpression implements Expression {
private int number;
private Compare compare;
public TerminalExpression(int number, Compare compare) {
this.number = number;
this.compare = compare;
}
public boolean interpret(int info) {
switch (compare) {
case GREATER:
return info > number;
case EQUAL:
return info == number;
case LESS:
return info < number;
}
return false;
}
enum Compare {
GREATER, EQUAL, LESS
}
}
package com.mine.design.interpreter;
public class AndExpression implements Expression {
private Expression expressionA;
private Expression expressionB;
public AndExpression(Expression expressionA, Expression expressionB) {
this.expressionA = expressionA;
this.expressionB = expressionB;
}
public boolean interpret(int info) {
return expressionA.interpret(info) && expressionB.interpret(info);
}
}
package com.mine.design.interpreter;
public class OrExpression implements Expression {
private Expression expressionA;
private Expression expressionB;
public OrExpression(Expression expressionA, Expression expressionB) {
this.expressionA = expressionA;
this.expressionB = expressionB;
}
public boolean interpret(int info) {
return expressionA.interpret(info) || expressionB.interpret(info);
}
}
package com.mine.design.interpreter;
import com.mine.design.interpreter.TerminalExpression.Compare;
public class Context {
private Expression ageExpression;
private Expression heightExpression;
public Context(int age, int height) {
// 大于等于age
Expression expression1 = new TerminalExpression(age, Compare.GREATER);
Expression expression2 = new TerminalExpression(age, Compare.EQUAL);
ageExpression = new OrExpression(expression1, expression2);
// 身高小于等于height
Expression expression3 = new TerminalExpression(height, Compare.LESS);
Expression expression4 = new TerminalExpression(height, Compare.EQUAL);
heightExpression = new OrExpression(expression3, expression4);
}
public boolean operation(int age, int height) {
return ageExpression.interpret(age) || heightExpression.interpret(height);
}
}
package com.mine.design.interpreter;
import java.util.ArrayList;
import java.util.List;
public class Client {
public static void main(String[] args) throws Exception {
List<Passenger> passengerList = new ArrayList<Passenger>();
Passenger p1 = new Passenger();
p1.setName("张一");
p1.setAge(65);
p1.setHeight(170);
passengerList.add(p1);
Passenger p2 = new Passenger();
p2.setName("张二");
p2.setAge(66);
p2.setHeight(172);
passengerList.add(p2);
Passenger p3 = new Passenger();
p3.setName("张三");
p3.setAge(45);
p3.setHeight(173);
passengerList.add(p3);
Passenger p4 = new Passenger();
p4.setName("张四");
p4.setAge(35);
p4.setHeight(175);
passengerList.add(p4);
Passenger p5 = new Passenger();
p5.setName("张五");
p5.setAge(10);
p5.setHeight(135);
passengerList.add(p5);
Passenger p6 = new Passenger();
p6.setName("张六");
p6.setAge(8);
p6.setHeight(130);
passengerList.add(p6);
Passenger p7 = new Passenger();
p7.setName("张七");
p7.setAge(6);
p7.setHeight(120);
passengerList.add(p7);
System.out.println("====所有人员信息====");
for (Passenger passenger : passengerList) {
System.out.println(passenger.toString());
}
System.out.println("====所有年龄大于等于65或者身高小于等于130人员免费乘车====");
for (Passenger passenger : passengerList) {
Context context = new Context(65, 130);
if (context.operation(passenger.getAge(), passenger.getHeight())) {
System.out.println(passenger.getName() + "免费乘车");
} else {
System.out.println(passenger.getName() + "乘车收费");
}
}
}
}