书接上回,本篇讲一下行为型模式-解释器模式
解释器模式
定义:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
大白话:设计一个程序,能解析拥有一定规则的表达式。比如正则表达式解析器。
UML图:
Expression:定义语法解析器的接口,约定解析器的解释操作
/**
* 语法表达式
*/
public interface Expression {
/**
* 语法解析
*/
void interpret();
}
Interpret1Expression/Interpret2Expression:表达式解析器,解析表达式中特定语法,一个解析器对应一个语法规则。
/**
* 子表达式(解析1)
* 负责完整表达式中一段解析
*/
public class Interpret1Expression implements Expression{
@Override
public void interpret() {
System.out.println("解析表达式中一段:子表达式1");
}
}
/**
* 子表达式(解析2)
* 负责完整表达式中一段解析
*/
public class Interpret2Expression implements Expression{
@Override
public void interpret() {
System.out.println("解析表达式中一段:子表达式2");
}
}
TerminalExpression:也是一个表达式解析器,一般表示终结,得出结果的语法,比如四则运算中,最后等于操作。
/**
* 子表达式(解析3)
* 负责完整表达式中一段解析--表示解析终止
*/
public class TerminalExpression implements Expression{
@Override
public void interpret() {
System.out.println("解析表达式中一段:终止表达式");
}
}
ExpressionInterpretParser:语法表达式解析器,这这个类中调用其他子解析器完整解析整个语法表达式式。担当总控的角色。
/**
* 表达式解析器
*/
public class ExpressionInterpretParser {
/**
* 指定表达式解析
* @param express
*/
public void parse(String express){
System.out.println("表达式:" + express);
System.out.println("调用解析器:" );
new Interpret1Expression().interpret();
new Interpret2Expression().interpret();
new TerminalExpression().interpret();
}
}
App:客户端,上面逻辑调用者。
public class App {
public static void main(String[] args) {
ExpressionInterpretParser interpret = new ExpressionInterpretParser();
interpret.parse("这是一个表达式");
}
}
结果:
表达式:这是一个表达式
调用解析器:
解析表达式中一段:子表达式1
解析表达式中一段:子表达式2
解析表达式中一段:终止表达式
案例分析
需求:设计一个解析器,能解析加减乘除运算
最终表达式:1 2 3 4 5 + - * /
预想结果: (((1+2)-3) *4) / 5 = 0
Expression:定义解析解析语法规则
SubExpression / MulExpression / DivExpression / AddExpression:分别是加减乘除语法解析规则实现
NumExpression:数字语法解析规则实现
ExpressionInterpretParser:规则解析器
App:客户端
具体解析规则类:
AddExpression
//加法
public class AddExpression implements Expression{
private Expression num1Expression; //第一个加数
private Expression num2Expression; //第二个加数
public AddExpression(Expression num1Expression, Expression num2Expression){
this.num1Expression = num1Expression;
this.num2Expression = num2Expression;
}
@Override
public int interpret() {
return num1Expression.interpret() + num2Expression.interpret();
}
@Override
public String toString() {
return "+";
}
}
SubExpression
//减法
public class SubExpression implements Expression{
private Expression num1Expression; //第一个减数
private Expression num2Expression; //第二个减数
public SubExpression(Expression num1Expression, Expression num2Expression){
this.num1Expression = num1Expression;
this.num2Expression = num2Expression;
}
@Override
public int interpret() {
return num1Expression.interpret() - num2Expression.interpret();
}
@Override
public String toString() {
return "-";
}
}
MulExpression
//乘法
public class MulExpression implements Expression{
private Expression num1Expression; //第一个乘数
private Expression num2Expression; //第二个乘数
public MulExpression(Expression num1Expression, Expression num2Expression){
this.num1Expression = num1Expression;
this.num2Expression = num2Expression;
}
@Override
public int interpret() {
return num1Expression.interpret() * num2Expression.interpret();
}
@Override
public String toString() {
return "*";
}
}
DivExpression
//乘法
public class DivExpression implements Expression{
private Expression num1Expression; //第一个除数
private Expression num2Expression; //第二个除数
public DivExpression(Expression num1Expression, Expression num2Expression){
this.num1Expression = num1Expression;
this.num2Expression = num2Expression;
}
@Override
public int interpret() {
return num1Expression.interpret() / num2Expression.interpret();
}
@Override
public String toString() {
return "/";
}
}
ExpressionInterpretParser
public class ExpressionInterpretParser {
private LinkedList<Expression> list = new LinkedList<>();
private boolean isSymbol(String sy){
return "+".equals(sy) || "-".equals(sy) || "*".equals(sy)|| "/".equals(sy);
}
private Integer operation(Expression num1, Expression num2, String symbol){
if("+".equals(symbol)){
return new AddExpression(num1,num2).interpret();
}else if("-".equals(symbol)){
return new SubExpression(num1,num2).interpret();
}else if("*".equals(symbol)){
return new MulExpression(num1,num2).interpret();
}else if("/".equals(symbol)){
return new DivExpression(num1,num2).interpret();
}
return null;
}
public void parse(String express){
String[] items = express.split(" ");
for (String item : items) {
if(!this.isSymbol(item)){
list.addLast(new NumExpression(item));
System.out.println("入栈参数:" + item);
}else{
System.out.println("运算符:" + item);
Expression num1 = list.removeFirst();
Expression num2 = list.removeFirst();
Integer ret = this.operation(num1, num2, item);
if(ret == null){
System.out.println("表达式解析异常,无法运算");
return;
}
this.list.push(new NumExpression(ret));
System.out.println("运算结果再入栈:" + ret);
}
}
if(list.size() == 1){
System.out.println("表达式运算结果:" + list.removeFirst());
}
}
}
App
public class App {
public static void main(String[] args) {
new ExpressionInterpretParser().parse("1 2 3 4 5 + - * /");
}
}
结果:
入栈参数:1
入栈参数:2
入栈参数:3
入栈参数:4
入栈参数:5
运算符:+
运算结果再入栈:3
运算符:-
运算结果再入栈:0
运算符:*
运算结果再入栈:0
运算符:/
运算结果再入栈:0
表达式运算结果:0
解析
加减乘除规则解析类,实现+-*/四则运算逻辑,将计算出结果重新入队列,参与后续计算。
适用场景
一些规则引擎解析
一些确定语法表达式需要解析时
一些重复出现的问题可以用一种简单的语言来进行表达。
优缺点
优点
语法由很多类表示,容易改变及扩展,新增表达式时,只需要添加新的表达式实现类即可,“开闭原则”。
缺点
当语法规则数目太多时,增加系统复杂度
开发案例
Spring自带了SpEl表达式
public class SpringELTest {
public static void main(String[] args) {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("(((1+2)-3) *4) / 5 ");
System.out.println(expression.getValue());
}
}
类体系:
解析体系类:ExpressionParser
public interface ExpressionParser {
Expression parseExpression(String expressionString) throws ParseException;
Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}
解析器实现类:SpelExpressionParser
public class SpelExpressionParser extends TemplateAwareExpressionParser {
@Override
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
}
}
父类解析器
public abstract class TemplateAwareExpressionParser implements ExpressionParser {
private Expression parseTemplate(String expressionString, ParserContext context) throws ParseException {
if (expressionString.isEmpty()) {
return new LiteralExpression("");
}
Expression[] expressions = parseExpressions(expressionString, context);
if (expressions.length == 1) {
return expressions[0];
}
else {
return new CompositeStringExpression(expressionString, expressions);
}
}
}
解析之后结果对象:Expression
public interface Expression {
//表达式规则
String getExpressionString();
//解析完后结果
@Nullable
Object getValue() throws EvaluationException;
}
总结
解析器模式在特定领域,特定场景下才使用,相对其他模式来说,使用频率不高得设计模式啦。
最后来总结一下:
解析器模式的本质:分离实现,解释执行。