当前位置: 移动技术网 > IT编程>软件设计>设计模式 > 设计模式之解释器模式(附:SpelExpressionParser中解释器模式应用分析)

设计模式之解释器模式(附:SpelExpressionParser中解释器模式应用分析)

2020年07月28日  | 移动技术网IT编程  | 我要评论

一、定义

1、定义

        Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.(给定一门语言,定义它的语法的一种表示,并定义一个解释器,该解释器使用该解释来解释语言中的句子。)

2、通用类图

在这里插入图片描述

3、基本介绍

        解释器模式是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)。
        在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法解析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器可以看作是解释器。

二、通用源码

解释器角色:

//抽象解释器
public abstract class Expression {

    //解析任务
    public abstract Object interpreter(Context ctx);
}

终结符表达式——TerminalExpression:
        实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的实例。

//终结符表达式
public class TerminalExpression extends Expression {
    @Override
    public Object interpreter(Context ctx) {
        return null;
    }
}

非终结符表达式——NonterminalExpression:
        文法中的每条规则对应一个非终结表达式。非终结表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

public class NonterminalExpression extends Expression {
    
    //每个非终结符表达式都会对其它表达式产生依赖
    public NonterminalExpression(Expression... expressions){
        
    }
    
    @Override
    public Object interpreter(Context ctx) {
        //进行文法处理
        return null;
    }
}

        每个非终结表达式都代表了一个文法规则,并且每个文法规则都只关心自己周边的文法规则的结果,因此这就产生了每个非终结符表达式调用自己周边的非终结符表达式,最终,最小的文法规则就是终结符表达式。
Client端调用:
        通常Client是一个封装类,封装的结果就是传递进来一个规范语法文件,解析器分析后产生结果并返回,避免了调用者与语法解析器的耦合关系。

public class Client {
    
    public static void main(String[] args){
        Context ctx=new Context();
        //定义一个语法容器,容纳一个具体的表达式;
        Stack<Expression> stack=null;
        
        for (;;){
            //进行语法分析,并产生递归调用
        }
        //产生一个完整的语法树,由各个具体的语法分析进行解析
        Expression exp=stack.pop();
        //j具体元素进入场景
        exp.interpreter(ctx);
    }
}

三、解释器模式的应用

1、优点
  • 良好的扩展性:修改语法规则只要修改相应的非终结表达式就可以了,若扩展语法,只要增加非终结符类就可以了。
2、缺点
  • 解释器模式会引起类膨胀:每一个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来许多麻烦。
  • 效率问题:解释器模式由于使用了大量的循环和递归,效率是一个不容忽视的问题。
3、使用场景
  • 重复发生的问题可以使用解释器模式:例如,多个应用服务器,需要对日志文件进行分析处理,由于各个服务器的日志格式不同,但是数据要素是相同的,按照解释器的说法就是终结符表达式都是相通的,但是非终结符表达式就需要制定了。在这种情况下,可以通过解释器模式一劳永逸的解决该问题。
  • 一个简单语法需要解释的场景:一般用于解析比较标准的字符集,例如SQL语法分析。

四、SpelExpressionParser中解释器模式应用分析

1、类图分析

        在下面的类图中,Expression是一个接口,相当于我们解释器模式中的非终结符表达式,而ExpressionParser相当于终结符表达式。根据不同的Parser对象,返回不同的Expression对象。
在这里插入图片描述

2、部分源码分析

Expression接口:

//抽象的非终结符表达式
public interface Expression {
	Object getValue() throws EvaluationException;
	
	Object getValue(Object rootObject) throws EvaluationException;
}

SpelExpression类:

//具体的非终结符表达式
public class SpelExpression implements Expression {
	@Override
	public Object getValue() throws EvaluationException {
		Object result;
		if (this.compiledAst != null) {
			try {
				TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject();
				return this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext);
			}
			catch (Throwable ex) {
				// If running in mixed mode, revert to interpreted
				if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
					this.interpretedCount = 0;
					this.compiledAst = null;
				}
				else {
					// Running in SpelCompilerMode.immediate mode - propagate exception to caller
					throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
				}
			}
		}
		ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
		result = this.ast.getValue(expressionState);
		checkCompile(expressionState);
		return result;
	}

}

CompositeStringExpression:

//具体的非终结符表达式
public class CompositeStringExpression implements Expression {
	@Override
	public String getValue() throws EvaluationException {
		StringBuilder sb = new StringBuilder();
		for (Expression expression : this.expressions) {
			String value = expression.getValue(String.class);
			if (value != null) {
				sb.append(value);
			}
		}
		return sb.toString();
	}
}

ExpressionParser接口:

public interface ExpressionParser {
	//解析表达式
	Expression parseExpression(String expressionString) throws ParseException;
	Expression parseExpression(String expressionString, ParserContext context) throws ParseException;
}

TemplateAwareExpressionParser类:

public abstract class TemplateAwareExpressionParser implements ExpressionParser {
	@Override
	public Expression parseExpression(String expressionString) throws ParseException {
		return parseExpression(expressionString, NON_TEMPLATE_PARSER_CONTEXT);
	}

	//根据不同的parser返回不同的Expression对象
	@Override
	public Expression parseExpression(String expressionString, ParserContext context)
			throws ParseException {
		if (context == null) {
			context = NON_TEMPLATE_PARSER_CONTEXT;
		}

		if (context.isTemplate()) {
			return parseTemplate(expressionString, context);
		}
		else {
			return doParseExpression(expressionString, context);
		}
	}

	private Expression parseTemplate(String expressionString, ParserContext context)
			throws ParseException {
		if (expressionString.length() == 0) {
			return new LiteralExpression("");
		}
		Expression[] expressions = parseExpressions(expressionString, context);
		if (expressions.length == 1) {
			return expressions[0];
		}
		else {
			return new CompositeStringExpression(expressionString, expressions);
		}
	}
	//抽象的,由子类去实现
	protected abstract Expression doParseExpression(String expressionString,
			ParserContext context) throws ParseException;
}

SpelExpressionParser类:

public class SpelExpressionParser extends TemplateAwareExpressionParser {
	@Override
	protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
		//这里返回了一个InternalSpelExpressionParser,
		return new InternalSpelExpressionParser(this.configuration).doParseExpression(expressionString, context);
	}

}

InternalSpelExpressionParser类:

class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
	@Override
	protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
		try {
			this.expressionString = expressionString;
			Tokenizer tokenizer = new Tokenizer(expressionString);
			tokenizer.process();
			this.tokenStream = tokenizer.getTokens();
			this.tokenStreamLength = this.tokenStream.size();
			this.tokenStreamPointer = 0;
			this.constructedNodes.clear();
			SpelNodeImpl ast = eatExpression();
			if (moreTokens()) {
				throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
			}
			Assert.isTrue(this.constructedNodes.isEmpty());
			return new SpelExpression(expressionString, ast, this.configuration);
		}
		catch (InternalParseException ex) {
			throw ex.getCause();
		}
	}
}

本文地址:https://blog.csdn.net/qq_42339210/article/details/107595568

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网