Java基于解释器模式实现定义一种简单的语言功能示例

作者:chengqiuming 时间:2021-06-18 15:53:42 

本文实例讲述了Java基于解释器模式实现定义一种简单的语言功能。分享给大家供大家参考,具体如下:

一 模式定义

解释器模式:就是给定一个语言的文法表示,并且定义一个解释器,用来解释语言中的句子。解释器模式描述了怎样在有了一个简单的文法后,使用模式设计解释这些语句。

二 模式举例

1 模式分析

我们自己设计一种语言来说明这一模式

(1)该语言区分大小写
(2)该语言以PROGRAM开头,END结尾
(3)PRINTLN表示打印一行并换行
(4)使用FOR…FROM…TO…END表示循环

示例语言内容如下:

PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end...END

该句表示的意思是:首先打印“start…”换行,然后循环打印“90”换行、“91”换行、……“100”换行,最后打印“end…”换行。

2 该语言解释树结构

Java基于解释器模式实现定义一种简单的语言功能示例

3 该语言解释器活动图

Java基于解释器模式实现定义一种简单的语言功能示例

4 代码示例

4.1 创建上下文环境——Context


package com.demo.interpreter.context;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
/**
* 上下文环境
*
* @author
*
*/
public class Context {
 // 待解析的文本内容
 private final StringTokenizer stringTokenizer;
 // 当前命令
 private String currentToken;
 // 用来存储动态变化信息内容
 private final Map<String, Object> map = new HashMap<String, Object>();
 /**
  * 构造方法设置解析内容
  *
  * @param text
  */
 public Context(String text) {
   // 使用空格分隔待解析文本内容
   this.stringTokenizer = new StringTokenizer(text);
 }
 /**
  * 解析文本
  */
 public String next() {
   if (this.stringTokenizer.hasMoreTokens()) {
     currentToken = this.stringTokenizer.nextToken();
   } else {
     currentToken = null;
   }
   return currentToken;
 }
 /**
  * 判断命令是否正确
  *
  * @param command
  * @return
  */
 public boolean equalsWithCommand(String command) {
   if (command == null || !command.equals(this.currentToken)) {
     return false;
   }
   return true;
 }
 /**
  * 获得当前命令内容
  *
  * @return
  */
 public String getCurrentToken() {
   return this.currentToken;
 }
 /**
  * 获得节点的内容
  *
  * @return
  */
 public String getTokenContent(String text) {
   String str = text;
   if (str != null) { // 替换map中的动态变化内容后返回 Iterator<String>
     // 替换map中的动态变化内容后返回
     Iterator<String> iterator = this.map.keySet().iterator();
     while (iterator.hasNext()) {
       String key = iterator.next();
       Object obj = map.get(key);
       str = str.replaceAll(key, obj.toString());
     }
   }
   return str;
 }
 public void put(String key, Object value) {
   this.map.put(key, value);
 }
 public void clear(String key) {
   this.map.remove(key);
 }
}

4.2 表达式接口——IExpressions


package com.demo.interpreter.express;
import com.demo.interpreter.context.Context;
/**
*
* 表达式接口
*
* @author
*
*/
public interface IExpressions {
 /**
  * 解析
  *
  * @param context
  */
 public void parse(Context context);
 /**
  * 执行方法
  *
  * @param context
  */
 public void interpret();
}

4.3 主表达式——ProgramExpression


package com.demo.interpreter.express;
import com.demo.interpreter.context.Context;
/**
* program 表达式
*
* @author
*
*/
public class ProgramExpression implements IExpressions {
 // 上下文环境
 private final Context context;
 // 当前命令
 private final static String COMMAND = "PROGRAM";
 // 存储下一个表达式引用
 private IExpressions expressions;
 /**
  * 构造方法将待解析的内容传入
  *
  * @param text
  */
 public ProgramExpression(String text) {
   this.context = new Context(text);
   this.parse(this.context);
 }
 @Override
 public void parse(Context context) {
   // 获取第一个命令节点
   this.context.next();
 }
 /**
  * 实现解释方法
  */
 @Override
 public void interpret() {
   // 判断是否是以PROGRAM 开始
   if (!this.context.equalsWithCommand(COMMAND)) {
     System.out.println("The '" + COMMAND + "' is Excepted For Start!");
   } else {
     // 是以PROGRAM 开始
     this.context.next();
     this.expressions = new ListExpression();
     this.expressions.parse(this.context);
     // ListExpression表达式开始解析
     this.expressions.interpret();
   }
 }
}

4.4 列表表达式——ListExpression


package com.demo.interpreter.express;
import java.util.ArrayList;
import java.util.Iterator;
import com.demo.interpreter.context.Context;
/**
* 列表表达式
*
* @author
*
*/
public class ListExpression implements IExpressions {
 private Context context;
 private final ArrayList<IExpressions> list = new ArrayList<IExpressions>();
 /**
  * 构造方法将待解析的context传入
  *
  * @param context
  */
 public void parse(Context context) {
   this.context = context;
   // 在ListExpression解析表达式中,循环解释语句中的每一个单词,直到终结符表达式或者异常情况退出
   while (true) {
     if (this.context.getCurrentToken() == null) {
       // 获取当前节点如果为 null 则表示缺少END表达式
       System.out.println("Error: The Experssion Missing 'END'! ");
       break;
     } else if (this.context.equalsWithCommand("END")) {
       this.context.next();
       // 解析正常结束
       break;
     } else {
       // 建立Command 表达式
       IExpressions expressions = new CommandExperssion(this.context);
       // 添加到列表中
       list.add(expressions);
     }
   }
 }
 /**
  * 实现解释方法
  */
 @Override
 public void interpret() {
   // 循环list列表中每一个表达式 解释执行
   Iterator<IExpressions> iterator = list.iterator();
   while (iterator.hasNext()) {
     (iterator.next()).interpret();
   }
 }
}

4.5 命令表达式——CommandExperssion


package com.demo.interpreter.express;
import com.demo.interpreter.context.Context;
/**
* 命令表达式
*
* @author
*
*/
public class CommandExperssion implements IExpressions {
 private final Context context;
 private IExpressions expressions;
 /**
  * 构造方法将待解析的context传入
  *
  * @param context
  */
 public CommandExperssion(Context context) {
   this.context = context;
   this.parse(this.context);
 }
 public void parse(Context context) {
   // 判断当前命令类别 在此只对For和最原始命令进行区分
   if (this.context.equalsWithCommand("FOR")) {
     // 创建For表达式进行解析
     expressions = new ForExpression(this.context);
   } else {
     // 创建原始命令表达式进行内容解析
     expressions = new PrimitiveExpression(this.context);
   }
 }
 /**
  * 解析内容
  */
 @Override
 public void interpret() {
   // 解析内容
   this.expressions.interpret();
 }
}

4.6 循环表达式——ForExpression


package com.demo.interpreter.express;
import com.demo.interpreter.context.Context;
/**
* For表达式
*
* @author
*
*/
public class ForExpression implements IExpressions {
 private final Context context;
 // 存储当前索引key值
 private String variable;
 // 存储循环起始位置
 private int start_index;
 // 存储循环结束位置
 private int end_index;
 private IExpressions expressions;
 /**
  * 构造方法将待解析的context传入
  *
  * @param context
  */
 public ForExpression(Context context) {
   this.context = context;
   this.parse(this.context);
 }
 /**
  * 解析表达式
  */
 @Override
 public void parse(Context context) {
   // 首先获取当前节点
   this.context.next();
   while (true) {
     // 判断节点
     if (this.context.equalsWithCommand("FROM")) {
       // 设置开始索引内容
       String nextStr = this.context.next();
       try {
         this.start_index = Integer.parseInt(nextStr);
       } catch (Exception e) {
         System.out
             .println("Error: After 'FROM' Expression Exist Error!Please Check the Format Of Expression is Correct!");
         break;
       }
       // 获取下一个节点
       this.context.next();
     } else if (this.context.equalsWithCommand("TO")) {
       // 设置结束索引内容
       String nextStr = this.context.next();
       try {
         this.end_index = Integer.parseInt(nextStr);
       } catch (Exception e) {
         System.out
             .println("Error: After 'TO' Expression Exist Error!Please Check the Format Of Expression is Correct!");
       }
       this.context.next();
       break;
     } else {
       // 设置当前索引变量内容
       if (this.variable == null) {
         this.variable = this.context.getCurrentToken();
       }
       // 获取下一个节点
       this.context.next();
     }
   }
   // 建立列表表达式
   this.expressions = new ListExpression();
   this.expressions.parse(this.context);
 }
 /**
  * 实现解释方法
  */
 @Override
 public void interpret() {
   // 建立命令表达式
   for (int x = this.start_index; x <= this.end_index; x++) {
     // 设置变量内容
     this.context.put("" + this.variable, x);
     // 执行解释方法
     this.expressions.interpret();
   }
   // 移除使用的临时变量内容
   this.context.clear("" + this.variable);
 }
}

4.7 基础表达式——PrimitiveExpression


package com.demo.interpreter.express;
import com.demo.interpreter.context.Context;
/**
* 最基础的表达式
*
* @author
*
*/
public class PrimitiveExpression implements IExpressions {
 private Context context;
 // 节点名称
 private String tokenName;
 // 文本内容
 private String text;
 /**
  * 构造方法将待解析的context传入
  *
  * @param context
  */
 public PrimitiveExpression(Context context) {
   this.parse(context);
 }
 @Override
 public void parse(Context context) {
   this.context = context;
   this.tokenName = this.context.getCurrentToken();
   this.context.next();
   if ("PRINTLN".equals(this.tokenName)) {
     this.text = this.context.getCurrentToken();
     this.context.next();
   }
 }
 /**
  * 实现解释方法
  */
 @Override
 public void interpret() {
   // 首先获取当前节点内容
   if ("PRINTLN".equals(tokenName)) {
     // 获得内容信息
     // 打印内容
     System.out.println(this.context.getTokenContent(this.text));
   }
 }
}

4.8 让语言解释器开始工作——Client


package com.demo.interpreter;
import com.demo.interpreter.express.IExpressions;
import com.demo.interpreter.express.ProgramExpression;
/**
* 主应用程序
*
* @author
*
*/
public class Client {
 /**
  * @param args
  */
 public static void main(String[] args) {
   // myida语言语句
   String str = "PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END";
   System.out.println("str:" + str);
   // 创建PROGRAM表达式
   IExpressions expressions = new ProgramExpression(str);
   // 解释执行
   expressions.interpret();
 }
}

5 运行结果

str:PROGRAM PRINTLN start... FOR i FROM 90 TO 100 PRINTLN i END PRINTLN end... END
start...
90
91
92
93
94
95
96
97
98
99
100
end...

三 设计原则

1 “开-闭”原则

2 封闭变化原则

四 使用场合

(1)一种特定类型的问题发生的频率足够高,并且业务规则频繁变化,不断重复出现类似情况。

(2)业务规则不是过于复杂烦琐,比较容易抽象出语法规则。

(3)效率不是软件系统中主要考虑的因素。

五 解释器模式静态类图

Java基于解释器模式实现定义一种简单的语言功能示例

更多java相关内容感兴趣的读者可查看本站专题:《Java面向对象程序设计入门与进阶教程》、《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

来源:https://blog.csdn.net/chengqiuming/article/details/70139382

标签:Java,解释器模式
0
投稿

猜你喜欢

  • Android 7.0 Nougat不得不知的11项新功能

    2021-06-12 22:50:07
  • 基于java文件上传-原始的Servlet方式

    2021-10-17 13:26:25
  • DevExpress实现GridControl根据列选中一行

    2021-08-16 05:23:19
  • .NET WinForm实现在listview中添加progressbar的方法

    2021-10-08 20:23:54
  • 详解SpringBoot多跨域请求的支持(JSONP)

    2023-09-21 04:12:54
  • jdk15的安装与配置全过程记录

    2023-01-06 05:45:10
  • Java网络编程之TCP程序设计

    2023-10-29 15:53:32
  • Android从0到完整项目(1)使用Android studio 创建项目详解

    2022-12-13 13:48:21
  • android TabLayout使用方法详解

    2021-08-06 07:52:17
  • Java 使用Docker时经常遇到的五个问题

    2023-12-10 07:20:21
  • Java高级架构之FastDFS分布式文件集群详解

    2023-07-23 14:57:50
  • C#实现简单的RSA非对称加密算法示例

    2022-07-09 18:16:37
  • Android设置全屏代码分享

    2022-03-25 10:42:30
  • 基于Java信号量解决死锁过程解析

    2023-05-13 22:23:02
  • Android利用手势完成屏幕密码锁功能

    2023-04-08 21:21:40
  • android studio使用SQLiteOpenHelper()建立数据库的方法

    2023-10-28 12:50:35
  • Android基于高德地图完全自定义Marker的实现方法

    2023-03-09 03:32:30
  • spring cloud gateway中如何读取请求参数

    2021-08-19 16:19:02
  • c#基数排序Radix sort的实现方法

    2021-07-25 02:02:21
  • spring boot使用logback实现多环境日志配置详解

    2022-10-03 20:38:24
  • asp之家 软件编程 m.aspxhome.com