解释器模式是一种行为型设计模式,它提供了一种方法来解释语言、表达式或符号。
在该模式中,定义了一个表达式接口,并实现了对应的表达式类,这些类可以解释不同的符号组成的表达式,从而实现对语言的解释。
场景
这种模式常常被用在编译器、解释器和正则表达式库中。该模式的核心思想是将一个复杂的问题分解成许多简单的问题,并将这些问题之间的关系表示为一种语法规则。
优点
缺点
注意
解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。
四大角色
interpret
, 交由子类进行具体解释。以根据乘客年龄和身高来判断乘坐公交车是否免费为例:
1.定义乘客
/**
* 乘客
*/
@Data
@AllArgsConstructor
public class Passenger {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private Integer age;
/**
* 身高
*/
private Double height;
}
2.定义表达式
/**
* 表达式
*/
public interface Expression {
/**
* 解释年龄
* @param age 年龄
* @return 解释结果
*/
boolean interpret(int age);
/**
* 解释身高
* @param height 身高
* @return 解释结果
*/
boolean interpret(double height);
}
3.定义比较器(枚举)
/**
* 比较器
*/
public enum Compare {
/**
* 较大
*/
GT,
/**
* 相等
*/
EQ,
/**
* 较小
*/
LT
}
4.定义终结符表达式
/**
* 终结符表达式
*/
public class TerminalExpression implements Expression {
/**
* 年龄
*/
private Integer age;
/**
* 身高
*/
private Double height;
/**
* 比较器
*/
private final Compare compare;
/**
* 构造年龄比较
* @param age 年龄
* @param compare 比较器
*/
public TerminalExpression(int age, Compare compare) {
this.age = age;
this.compare = compare;
}
/**
* 构造身高比较
* @param height 身高
* @param compare 比较器
*/
public TerminalExpression(double height, Compare compare) {
this.height = height;
this.compare = compare;
}
@Override
public boolean interpret(int age) {
// 比较年龄大小
switch (compare) {
// 较大
case GT:
return age > this.age;
// 相等
case EQ:
return age == this.age;
// 较小
case LT:
return age < this.age;
default:
return false;
}
}
@Override
public boolean interpret(double height) {
// 比较身高大小
switch (compare) {
// 较大
case GT:
return height > this.height;
// 相等
case EQ:
return height == this.height;
// 较小
case LT:
return height < this.height;
default:
return false;
}
}
}
5.定义非终结符表达式
①与表达式:
/**
* 与表达式
*/
public class AndExpression implements Expression {
/**
* 表达式1
*/
private Expression expression1;
/**
* 表达式2
*/
private Expression expression2;
/**
* 构造表达式
* @param expression1 表达式1
* @param expression2 表达式2
*/
public AndExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
@Override
public boolean interpret(int age) {
return this.expression1.interpret(age) && this.expression2.interpret(age);
}
@Override
public boolean interpret(double height) {
return this.expression1.interpret(height) && this.expression2.interpret(height);
}
}
②或表达式:
/**
* 或表达式
*/
public class OrExpression implements Expression {
/**
* 表达式1
*/
private Expression expression1;
/**
* 表达式2
*/
private Expression expression2;
/**
* 构造表达式
* @param expression1 表达式1
* @param expression2 表达式2
*/
public OrExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
@Override
public boolean interpret(int age) {
return this.expression1.interpret(age) || this.expression2.interpret(age);
}
@Override
public boolean interpret(double height) {
return this.expression1.interpret(height) || this.expression2.interpret(height);
}
}
6.定义免费标准
/**
* 免费标准
*/
public class Free {
/**
* 年龄表达式
*/
private Expression ageExpression;
/**
* 身高表达式
*/
private Expression heightExpression;
/**
* 构造免费情况
* @param age 年龄
* @param height 身高
*/
public Free(int age, double height) {
// 大于等于设定年龄
Expression expression1 = new TerminalExpression(age, Compare.GT);
Expression expression2 = new TerminalExpression(age, Compare.EQ);
ageExpression = new OrExpression(expression1, expression2);
// 小于等于设定身高
expression1 = new TerminalExpression(height, Compare.LT);
expression2 = new TerminalExpression(height, Compare.EQ);
heightExpression = new OrExpression(expression1, expression2);
}
/**
* 结果
* @param age 年龄
* @param height 身高
* @return 判定结果
*/
public boolean adjust(int age, double height) {
return ageExpression.interpret(age) || heightExpression.interpret(height);
}
}
7.调用
// 定义乘客集合
List list = new ArrayList<>();
Passenger p1 = new Passenger("张三", 65, 170.0);
Passenger p2 = new Passenger("李四", 10, 130.0);
Passenger p3 = new Passenger("王五", 50, 170.0);
list.add(p1);
list.add(p2);
list.add(p3);
list.forEach(p->{
// 定义免费标准
Free free = new Free(65, 130);
// 满足条件则免费
if (free.adjust(p.getAge(), p.getHeight())) {
System.out.println(p.getName() + ":免费");
}// 不满足条件则正常收费
else {
System.out.println(p.getName() + ":刷卡或投币");
}
});
控制台输出:
可以看到,这里按照预期输出了结果,实现了根据年龄和身高自动判断是否免费的功能。