设计模式之解释器模式

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 设计模式之解释器模式
一、定义
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,如有侵权,请联系删除。

相关文章
|
设计模式 移动开发 数据库
行为型设计模式10-解释器模式
行为型设计模式10-解释器模式
102 1
|
3月前
|
设计模式 存储 缓存
Java设计模式 - 解释器模式(24)
Java设计模式 - 解释器模式(24)
|
7月前
|
设计模式 SQL Java
【设计模式】抖音一面:你不知道解释器模式?
【设计模式】抖音一面:你不知道解释器模式?
56 1
|
7月前
|
设计模式 Go
[设计模式 Go实现] 行为型~解释器模式
[设计模式 Go实现] 行为型~解释器模式
|
7月前
|
设计模式 存储 Java
小谈设计模式(28)—解释器模式
小谈设计模式(28)—解释器模式
|
7月前
|
设计模式 存储 Java
23种设计模式,解释器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第7天】解释器模式是一种行为设计模式,它用于定义一个语言的语法表示,并提供一个解释器来处理这种语法。主要用于频繁需要解释执行一组固定语法规则的场景,例如编程语言解释器、规则引擎等。
49 3
|
7月前
|
设计模式 存储 SQL
【设计模式系列笔记】解释器模式
解释器模式(Interpreter Pattern)是一种行为型设计模式,它定义了一种语言的文法,并且建立一个解释器来解释该语言中的句子。在Java中,解释器模式通常用于实现编程语言解释器、正则表达式解释器等。
78 0
|
7月前
|
设计模式
【设计模式】解释器模式
【设计模式】解释器模式
|
7月前
|
设计模式 监控 Java
聊聊Java设计模式-解释器模式
解释器模式(Interpreter Design Pattern)指给定一个“语言”,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。这里所指的“语言”是指使用规定格式和语法的代码。
88 4
聊聊Java设计模式-解释器模式
|
7月前
|
设计模式 Go 开发工具
Golang设计模式——18解释器模式
Golang设计模式——18解释器模式
52 0
Golang设计模式——18解释器模式