[设计模式/Java] 设计模式之解释器模式【27】

概述:解释器模式 := Interpreter Pattern ∈ 行为型模式

模式定义

  • 解释器模式Interpreter Pattern)提供了评估语言的语法表达式的方式

属于行为型模式

  • 解释器模式给定一个语言 ,定义它的文法的一种表示 ,并定义一个解释器 ,这个解释器 使用该表示来解释语言中的句子

  • 这种模式被用在 SQL 解析符号处理引擎等。

  • 模式的意图

定义一种语言的文法表示,并创建一个解释器,该解释器能够解释该语言中的句子。。

  • 主要解决的问题

解释器模式用于构建一个能够解释特定语言或文法句子的解释器

模式结构

解释器模式包含以下几个主要角色:

  • 抽象表达式(Abstract Expression):定义了解释器的抽象接口,声明了解释操作的方法,通常是一个抽象类或接口。
  • 终结符表达式(Terminal Expression):实现了抽象表达式接口的终结符表达式类,用于表示语言中的终结符(如变量、常量等),并实现了对应的解释操作。
  • 非终结符表达式(Non-terminal Expression):实现了抽象表达式接口的非终结符表达式类,用于表示语言中的非终结符(如句子、表达式等),并实现了对应的解释操作。
  • 上下文(Context) :包含解释器之外的一些全局 信息,在解释过程中提供给解释器使用,通常用于存储变量 的值、保存解释器的状态等。
  • 客户端(Client):创建并配置具体的解释器对象,并将需要解释的表达式传递给解释器进行解释。

适用场景

  • 当某一特定类型的问题频繁出现,并且可以通过一种简单的语言来表达这些问题的实例时。

实现方式

  • 定义【文法】:明确语言的终结符和非终结符。
  • 构建【语法树】:根据语言的句子构建对应的语法树结构。
  • 创建【环境类】:包含解释过程中所需的全局信息,通常是一个HashMap。

关键代码

  • 终结符与非终结符:定义语言的文法结构。
  • 环境类:存储解释过程中需要的外部环境信息。

模式特点

优点

  • 可扩展性好:容易添加新的解释表达式的方式。
  • 灵活性:可以根据需要轻松扩展或修改文法。
  • 易于实现简单文法:对于简单的语言,实现起来相对容易。

缺点

  1. 使用场景有限:只适用于适合使用解释的简单文法。
  2. 维护困难:对于复杂的文法,维护和扩展变得困难。
  3. 类膨胀:可能会产生很多类,每个文法规则对应一个类。
  4. 递归调用:解释器模式通常使用【递归调用】,这可能难以理解和跟踪。

使用建议

  • 在需要解释执行语言中的句子时,考虑使用解释器模式。
  • 确保文法简单,以避免系统变得过于复杂。
  • 解释器模式在 Java 中可能不是首选,如果遇到适用场景,可以考虑使用如expression4J之类的库来代替。

案例实践

案例总结

  • 编译器:解释器模式可以用于编译器设计,将源代码解释为目标代码。
  • 正则表达式:解释器模式可以用于解析和执行正则表达式。
  • SQL解析:解释器模式可以用于解析和执行SQL语句。
  • 文本模板渲染引擎 : 用于将各层级的环境信息渲染到文本模板中,生成最终的SQL、HTML等。著名的文本模板渲染引擎有:Jinjia(2) / Thymeleaf / Freemaker 等。

CASE 解释器模式的简单实现(性别/婚姻)

  • 我们将创建一个接口 Expression 和实现了 Expression 接口的实体类。
  • 定义作为上下文中主要解释器的 TerminalExpression 类。
  • 其他的类 OrExpression、AndExpression 用于创建组合式表达式
  • InterpreterPatternDemo,我们的演示类使用 Expression 类创建规则和演示表达式的解析。

表达式接口 : Expression

java 复制代码
public interface Expression {
   public boolean interpret(String context);
}

表达式接口的实现类: TerminalExpression / OrExpression / AndExpression

  • TerminalExpression
java 复制代码
public class TerminalExpression implements Expression {
   
   private String data;
 
   public TerminalExpression(String data){
      this.data = data; 
   }
 
   @Override
   public boolean interpret(String context) {
      if(context.contains(data)){
         return true;
      }
      return false;
   }
}
  • OrExpression
java 复制代码
public class OrExpression implements Expression {
   private Expression expr1 = null;
   private Expression expr2 = null;
 
   public OrExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }
 
   @Override
   public boolean interpret(String context) {      
      return expr1.interpret(context) || expr2.interpret(context);
   }
}
  • AndExpression
java 复制代码
public class AndExpression implements Expression {
   private Expression expr1 = null;
   private Expression expr2 = null;
 
   public AndExpression(Expression expr1, Expression expr2) { 
      this.expr1 = expr1;
      this.expr2 = expr2;
   }
 
   @Override
   public boolean interpret(String context) {      
      return expr1.interpret(context) && expr2.interpret(context);
   }
}

Client : InterpreterPatternDemo

  • InterpreterPatternDemo : 使用 Expression 类来创建规则,并解析它们。
java 复制代码
public class InterpreterPatternDemo {
   //规则:Robert 和 John 是男性
   public static Expression getMaleExpression(){
      Expression robert = new TerminalExpression("Robert");
      Expression john = new TerminalExpression("John");
      return new OrExpression(robert, john);    
   }
 
   //规则:Julie 是一个已婚的女性
   public static Expression getMarriedWomanExpression(){
      Expression julie = new TerminalExpression("Julie");
      Expression married = new TerminalExpression("Married");
      return new AndExpression(julie, married);    
   }
 
   public static void main(String[] args) {
      Expression isMale = getMaleExpression();
      Expression isMarriedWoman = getMarriedWomanExpression();
 
      System.out.println("John is male? " + isMale.interpret("John"));
      System.out.println("Julie is a married women? " 
      + isMarriedWoman.interpret("Married Julie"));
   }
}

out

log 复制代码
John is male? true
Julie is a married women? true

CASE 开源 SQL 解析引擎 - Apche Calcite

  • 推荐文献

CASE 开源语法分析工具 - Antlr

  • 推荐文献

Y 推荐文献

X 参考文献

相关推荐
卜及中38 分钟前
【Redis/2】核心特性、应用场景与安装配置
数据库·redis·缓存
LucianaiB1 小时前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
Eiceblue1 小时前
Python读取PDF:文本、图片与文档属性
数据库·python·pdf
敖云岚4 小时前
【Redis】分布式锁的介绍与演进之路
数据库·redis·分布式
LUCIAZZZ4 小时前
HikariCP数据库连接池原理解析
java·jvm·数据库·spring·springboot·线程池·连接池
胡侃有料5 小时前
【设计模式】1.简单工厂、工厂、抽象工厂模式
设计模式·抽象工厂模式
我在北京coding5 小时前
300道GaussDB(WMS)题目及答案。
数据库·gaussdb
小Tomkk5 小时前
阿里云 RDS mysql 5.7 怎么 添加白名单 并链接数据库
数据库·mysql·阿里云
明月醉窗台6 小时前
qt使用笔记二:main.cpp详解
数据库·笔记·qt
沉到海底去吧Go6 小时前
【图片自动识别改名】识别图片中的文字并批量改名的工具,根据文字对图片批量改名,基于QT和腾讯OCR识别的实现方案
数据库·qt·ocr·图片识别自动改名·图片区域识别改名·pdf识别改名