【Java开发】设计模式 12:解释器模式
1 解释器模式介绍
解释器模式是一种行为型设计模式,它提供了一种方法来解释语言、表达式或符号。
在该模式中,定义了一个表达式接口,并实现了对应的表达式类,这些类可以解释不同的符号组成的表达式,从而实现对语言的解释。
📌 场景
这种模式常常被用在编译器、解释器和正则表达式库中。该模式的核心思想是将一个复杂的问题分解成许多简单的问题,并将这些问题之间的关系表示为一种语法规则。
📌 优点
- 灵活性好:解释器模式能够灵活地处理复杂的或变化的语法规则,因为语法规则都是由解释器来进行解释和处理的。
- 易于修改和扩展:由于解释器模式中的文法以类的形式存在,所以增加新的文法规则和解释器相对容易。
📌 缺点
- 执行效率较低:因为使用解释器模式需要对文法规则进行解析和执行,而这个过程是比较耗时的,所以解释器模式的执行效率较低。
- 增加系统复杂性:因为解释器模式中的文法规则以类的形式存在,所以随着文法规则的增加,类的数量也会随之增加,这会增加系统的复杂性。
- 可维护性较差:由于解释器模式中的文法规则以类的形式存在,如果系统中存在大量的文法规则,那么系统的维护难度也会相应增加。
📌 注意
解释器模式在实际的软件开发中使用比较少,因为它会引起效率、性能以及维护等问题。如果碰到对表达式的解释,在 Java 中可以用 Expression4J 或 Jep 等来设计。
2 解释器模式实现
以根据乘客年龄和身高来判断乘坐公交车是否免费为例:
📌 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;}@Overridepublic 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;}}@Overridepublic 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;}@Overridepublic boolean interpret(int age) {return this.expression1.interpret(age) && this.expression2.interpret(age);}@Overridepublic 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;}@Overridepublic boolean interpret(int age) {return this.expression1.interpret(age) || this.expression2.interpret(age);}@Overridepublic 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<Passenger> 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() + ":刷卡或投币");}
});
控制台输出:
可以看到,这里按照预期输出了结果,实现了根据年龄和身高自动判断是否免费的功能。