设计模式之解释器模式

简介: 设计模式之解释器模式
一、定义
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,如有侵权,请联系删除。

相关文章
|
7月前
|
设计模式 移动开发 数据库
行为型设计模式10-解释器模式
行为型设计模式10-解释器模式
47 1
|
16天前
|
设计模式 存储 Java
小谈设计模式(28)—解释器模式
小谈设计模式(28)—解释器模式
|
2月前
|
设计模式
【设计模式】解释器模式
【设计模式】解释器模式
|
4月前
|
设计模式 监控 Java
聊聊Java设计模式-解释器模式
解释器模式(Interpreter Design Pattern)指给定一个“语言”,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。这里所指的“语言”是指使用规定格式和语法的代码。
37 4
聊聊Java设计模式-解释器模式
|
4月前
|
设计模式 Go 开发工具
Golang设计模式——18解释器模式
Golang设计模式——18解释器模式
22 0
Golang设计模式——18解释器模式
|
4月前
|
设计模式 存储 前端开发
【设计模式】之解释器模式
解释器模式是一种用于解释特定语言或规则的表达式的行为设计模式。在前端开发中,解释器模式可以用于处理复杂的逻辑或规则,并将其转化为可执行的代码。它具有灵活性和可扩展性的优点,但也存在复杂性和性能问题的缺点。通过合理地应用解释器模式,可以提高代码的可读性和可维护性,实现更灵活和可扩展的功能。
43 1
|
5月前
|
设计模式 存储 缓存
二十三种设计模式全面解析-探索解释器模式如何应对性能挑战
二十三种设计模式全面解析-探索解释器模式如何应对性能挑战
|
5月前
|
设计模式 存储 缓存
二十三种设计模式全面解析-探索解释器模式的高级应用和优化技巧:解锁代码解析的新境界
二十三种设计模式全面解析-探索解释器模式的高级应用和优化技巧:解锁代码解析的新境界
|
5月前
|
设计模式 自然语言处理 编译器
二十三种设计模式全面解析-解释器模式(Interpreter Pattern):用代码诠释语言的魅力
二十三种设计模式全面解析-解释器模式(Interpreter Pattern):用代码诠释语言的魅力
|
6月前
|
设计模式 自然语言处理 机器人
认真学习设计模式之解释器模式(Interpreter Pattern)
认真学习设计模式之解释器模式(Interpreter Pattern)
48 0