千家信息网

设计模式系列之什么是解释器模式

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,本篇内容主要讲解"设计模式系列之什么是解释器模式",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"设计模式系列之什么是解释器模式"吧!模式定义给分析对象定义一
千家信息网最后更新 2026年11月04日设计模式系列之什么是解释器模式

本篇内容主要讲解"设计模式系列之什么是解释器模式",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"设计模式系列之什么是解释器模式"吧!

模式定义

给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。也就是说,用编译语言的方式来分析应用中的实例。这种模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。

这里提到的文法和句子的概念同编译原理中的描述相同,"文法"指语言的语法规则,而"句子"是语言集中的元素。例如,汉语中的句子有很多,"我是中国人"是其中的一个句子,可以用一棵语法树来直观地描述语言中的句子。

模式的结构和实现

解释器模式常用于对简单语言的编译或分析实例中,为了掌握好它的结构与实现,必须先了解编译原理中的"文法、句子、语法树"等相关概念。

文法

文法是用于描述语言的语法结构的形式规则。没有规矩不成方圆,例如,有些人认为完美爱情的准则是"相互吸引、感情专一、任何一方都没有恋爱经历",虽然最后一条准则较苛刻,但任何事情都要有规则,语言也一样,不管它是机器语言还是自然语言,都有它自己的文法规则。例如,中文中的"句子"的文法如下。

  • 〈句子〉::=〈主语〉〈谓语〉〈宾语〉

  • 〈主语〉::=〈代词〉|〈名词〉

  • 〈谓语〉::=〈动词〉

  • 〈宾语〉::=〈代词〉|〈名词〉

  • 〈代词〉你|我|他

  • 〈名词〉7大学生I筱霞I英语

  • 〈动词〉::=是|学习

注:这里的符号"::="表示"定义为"的意思,用"〈"和"〉"括住的是非终结符,没有括住的是终结符。

句子

句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由"文法"推导出。例如,上述文法可以推出"我是大学生",所以它是句子。

语法树

语法树是句子结构的一种树型表示,它代表了句子的推导结果,它有利于理解句子语法结构的层次。下图所示是"我是大学生"的语法树。

解释器模式的结构与组合模式相似,不过其包含的组成元素比组合模式多,而且组合模式是对象结构型模式,而解释器模式是类行为型模式。

模式的实现

解释器模式实现的关键是定义文法规则、设计终结符类与非终结符类、画出结构图,必要时构建语法树,其代码结构如下:

package com.niuh.designpattern.interpreter.v1;  /**  * 

* 解释器模式 *

*/ public class InterpreterPattern { } //抽象表达式类 interface AbstractExpression { public Object interpret(String info); //解释方法 } //终结符表达式类 class TerminalExpression implements AbstractExpression { public Object interpret(String info) { //对终结符表达式的处理 return null; } } //非终结符表达式类 class NonterminalExpression implements AbstractExpression { private AbstractExpression exp1; private AbstractExpression exp2; public Object interpret(String info) { //非对终结符表达式的处理 return null; } } //环境类 class Context { private AbstractExpression exp; public Context() { //数据初始化 } public void operation(String info) { //调用相关表达式类的解释方法 } }

解决的问题

对于一些固定文法构建一个解释句子的解释器。

模式组成

实例说明

实例概况

用解释器模式设计一个北京公交车卡的读卡器程序。

说明:假如北京公交车读卡器可以判断乘客的身份,如果是"海淀区"或者"朝阳区"的"老人" "妇女""儿童"就可以免费乘车,其他人员乘车一次扣 2 元。

分析:本实例用"解释器模式"设计比较适合,首先设计其文法规则如下。

 ::= 的  ::= 海淀区|朝阳区  ::= 老人|妇女|儿童

然后,根据文法规则按以下步骤设计公交车卡的读卡器程序的类图。

使用步骤

步骤1:定义一个抽象表达式(Expression)接口,它包含了解释方法 interpret(String info)。

//抽象表达式类 interface Expression {     public boolean interpret(String info); }

步骤2:定义一个终结符表达式(Terminal Expression)类,它用集合(Set)类来保存满足条件的城市或人,并实现抽象表达式接口中的解释方法 interpret(Stringinfo),用来判断被分析的字符串是否是集合中的终结符。

class TerminalExpression implements Expression {     private Set set = new HashSet();      public Terminal_Expression(String[] data) {         for (int i = 0; i < data.length; i++) {             set.add(data[i]);         }     }      public boolean interpret(String info) {         if (set.contains(info)) {             return true;         }         return false;     } }

步骤3:定义一个非终结符表达式(AndExpressicm)类,它也是抽象表达式的子类,它包含满足条件的城市的终结符表达式对象和满足条件的人员的终结符表达式对象,并实现 interpret(String info) 方法,用来判断被分析的字符串是否是满足条件的城市中的满足条件的人员。

class AndExpression implements Expression {     private Expression city = null;     private Expression person = null;      public And_Expression(Expression city, Expression person) {         this.city = city;         this.person = person;     }      public boolean interpret(String info) {         String s[] = info.split("的");         return city.interpret(s[0]) && person.interpret(s[1]);     } }

步骤4:定义一个环境(Context)类,它包含解释器需要的数据,完成对终结符表达式的初始化,并定义一个方法 freeRide(String info) 调用表达式对象的解释方法来对被分析的字符串进行解释。

class Context {     private String[] citys = {"海淀区", "朝阳区"};     private String[] persons = {"老人", "妇女", "儿童"};     private Expression cityPerson;      public Context() {         Expression city = new Terminal_Expression(citys);         Expression person = new Terminal_Expression(persons);         cityPerson = new And_Expression(city, person);     }      public void freeRide(String info) {         boolean ok = cityPerson.interpret(info);         if (ok) {             System.out.println("您是" + info + ",您本次乘车免费!");         } else {             System.out.println(info + ",您不是免费人员,本次乘车扣费2元!");         }     } }

步骤5:客户端测试

public class InterpreterPattern {     public static void main(String[] args) {         Context bus = new Context();         bus.freeRide("海淀区的老人");         bus.freeRide("海淀区的年轻人");         bus.freeRide("朝阳区的妇女");         bus.freeRide("朝阳区的儿童");         bus.freeRide("南京的年轻人");     } }

输出结果

  • 您是海淀区的老人,您本次乘车免费!

  • 海淀区的年轻人,您不是免费人员,本次乘车扣费2元!

  • 您是朝阳区的妇女,您本次乘车免费!

  • 您是朝阳区的儿童,您本次乘车免费!

  • 南京的年轻人,您不是免费人员,本次乘车扣费2元!

优点

解释器模式是一种类行为型模式,其主要优点如下。

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。

  3. 容易实现。在语法树中的每个表达式节点类都是相似的,所以实现其文法较为容易。

缺点

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 执行效率较低。解释器模式中通常使用大量的循环和递归调用,当要解释的句子较复杂时,其运行速度很慢,且代码的调试过程也比较麻烦。

  3. 会引起类膨胀。解释器模式中的每条规则至少需要定义一个类,当包含的文法规则很多时,类的个数将急剧增加,导致系统难以管理与维护。

  4. 可应用的场景比较少。在软件开发中,需要定义语言文法的应用实例非常少,所以这种模式很少被使用到。

应用场景

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 当语言的文法较为简单,且执行效率不是关键问题时。

  3. 当问题重复出现,且可以用一种简单的语言来进行表达时。

  4. 当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。

模式的扩展

在项目开发中,如果要对数据表达式进行分析与计算,无须再用解释器模式进行设计了,Java 提供了以下强大的数学公式解析器:Expression4J、MESP(Math Expression String Parser) 和 Jep 等,它们可以解释一些复杂的文法,功能强大,使用简单。

现在以 Jep 为例来介绍该工具包的使用方法。Jep 是 Java expression parser 的简称,即 Java 表达式分析器,它是一个用来转换和计算数学表达式的 Java 库。通过这个程序库,用户可以以字符串的形式输入一个任意的公式,然后快速地计算出其结果。而且 Jep 支持用户自定义变量、常量和函数,它包括许多常用的数学函数和常量。

使用前先配置依赖包:

      jep     jep     2.24 

下面来看一个案例:

package com.niuh.designpattern.interpreter.v3;   import org.nfunk.jep.JEP;  /**  * 

* JepDemo *

*/ public class JepDemo { public static void main(String[] args) { JEP jep = new JEP(); //一个数学表达式 String exp = "((a+b)*(c+b))/(c+a)/b"; //给变量赋值 jep.addVariable("a", 10); jep.addVariable("b", 10); jep.addVariable("c", 10); try { //执行 jep.parse_Expression(exp); Object result = jep.getValueAsObject(); System.out.println("计算结果: " + result); } catch (Throwable e) { System.out.println("An error occured: " + e.getMessage()); } } }

程序运行结果如下:

  • 计算结果: 2.0

源码中的应用

SpelExpressionParser中解释器模式应用分析

类图分析

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

部分源码分析

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&nbsp;= 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 parse_Expression(String expressionString) throws ParseException;  Expression parse_Expression(String expressionString, ParserContext context) throws ParseException; }

TemplateAwareExpressionParser类

public abstract class TemplateAwareExpressionParser implements ExpressionParser {  @Override  public Expression parse_Expression(String expressionString) throws ParseException {   return parse_Expression(expressionString, NON_TEMPLATE_PARSER_CONTEXT);  }  //根据不同的parser返回不同的Expression对象  @Override  public Expression parse_Expression(String expressionString, ParserContext context)    throws ParseException {   if (context == null) {    context = NON_TEMPLATE_PARSER_CONTEXT;   }   if (context.isTemplate()) {    return parseTemplate(expressionString, context);   }   else {    return doParse_Expression(expressionString, context);   }  }  private Expression parseTemplate(String expressionString, ParserContext context)    throws ParseException {   if (expressionString.length() == 0) {    return new Literal_Expression("");   }   Expression[] expressions = parseExpressions(expressionString, context);   if (expressions.length == 1) {    return expressions[0];   }   else {    return new CompositeString_Expression(expressionString, expressions);   }  }  //抽象的,由子类去实现  protected abstract Expression doParse_Expression(String expressionString,    ParserContext context) throws ParseException; }

SpelExpressionParser类

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

InternalSpelExpressionParser类

class InternalSpelExpressionParser extends TemplateAwareExpressionParser {  @Override  protected SpelExpression doParse_Expression(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 = eat_Expression();    if (moreTokens()) {     throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken()));    }    Assert.isTrue(this.constructedNodes.isEmpty());    return new Spel_Expression(expressionString, ast, this.configuration);   }   catch (InternalParseException ex) {    throw ex.getCause();   }  } }

到此,相信大家对"设计模式系列之什么是解释器模式"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

模式 解释 表达式 文法 终结符 语言 解释器 句子 分析 语法 设计 规则 方法 结构 对象 接口 步骤 朝阳 朝阳区 海淀 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技公司的优势 互联网科技缩写 深圳天众互联网科技公司 互联网科技股午盘股票涨跌 互联网科技创新企业排名 互联网教育科技公司vipkid 互联网时代科技改变生活 湖南诚度互联网科技有限公司 武汉健翔互联网络科技有限公司 互联网5g黑科技有哪些 宜昌元轩互联网科技有限公司 恒生互联网科技指数跳水 如何创新互联网科技 南通创西澳互联网科技有限公司 新氧科技和美国互联网有关系吗 宁波跨境商互联网科技有限公司 吉林省码上互联网科技电话 唯美互联网科技 科技信息时代互联网发展 保山浩联互联网科技有限公司 A股互联网金融科技公司 互联网科技的 汇久创客互联网科技 北京三清互联网科技 科技互联网的估值 欧洲十大科技互联网公司 茂名市互联网科技产业园 受益于互联网科技的高速发展 每天都有哪些好的互联网科技 互联网科技的前景
0