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

本文实例讲述了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 该语言解释树结构

3 该语言解释器活动图

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操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

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

(0)

相关推荐

  • Java接口名称冲突问题的讲解

    对于方法重载的区分,主要通过下面三种方式: 1. 参数个数 2. 参数类型 3. 参数顺序(较少使用,维护困难) 至于方法的其他部分,如方法返回值类型.修饰符等,与方法重载则没有任何关系. Java编程时,假设存在两个接口,但接口中存在相同名称的方法,但是其仅返回值不同.如下: interface interfac1{ void method(); } interface interface2 { int method(); } interface interface3 extends inte

  • Java为什么基本数据类型不需要进行创建对象?

    Java是一门面向对象的语言,即一切皆是对象!那么为何数据类型中还分为:基本类型和对象? Java中有8种基本数据类型boolean.byte.short.char.int.flaot.long.double,基本数据类型作为Java语言的一部分,但基本数据类型不是对象,基本数据类型放在堆栈中,对象放在堆中.堆的读写速度远不及栈,如果使用基本数据类型相当于在栈上进行操作,对变量的创建和销毁速度非常快.相反,如果用类进行定义变量,需要在堆中进行操作,创建和销毁速度都比较慢. 出于性能方面的考量,为

  • 解析Java的设计模式编程之解释器模式的运用

    定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式.   解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器Nonter

  • 如何理解Java中基类子对象的构建过程从"基类向外"进行扩散的?

    <Java编程思想>复用类一章,提出基类的子对象的构建过程是从基类"向外"进行扩散的. 下面通过实例进行讲解,首先看下面的代码: import static net.mindview.util.Print.*; //<java编程思想>提供的类库 /** * @author Administrator * */ public class Cat extends Animal { public Cat() { // TODO Auto-generated cons

  • Java设计模式之解释器模式_动力节点Java学院整理

    定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式. 解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpression和非终结符解释器Nonterm

  • Java关于含有继承类的成员初始化过程讲解

    参考资料<Java 编程思想>,关于含有基类的导出类,其成员的初始化过程是一个容易让人困惑的地方,下面通过具体的实例进行讲解,代码取自<Java 编程思想>,代码如下: import static net.mindview.util.Print.*; /** * All rights Reserved, Designed By www.tydic.com * * @project: MyExerciseProject * @Title: Beetle.java * @Package

  • Java解释器的运行过程介绍

    首先介绍一下Java解释器的概念,Java解释器:解释器是Java虚拟机非常重要的一部分,它的工作就是把字节码转化为机器码并在特定的平台进行运行.简单一点,java的解释器只是一个基于虚拟机JVM平台的程序 ,即jdk或jre目录下bin目录中的java.exe文件. Java解释器相当于运行Java字节码的"CPU",但该"CPU"不是通过硬件实现的,而是用软件实现的. 步骤1:可以通过操作系统设置,也可不用设置,一般编译环境会为你设置,其中CLASSPATH包含

  • 23种设计模式(15)java解释器模式

    23种设计模式第十五篇:java解释器模式 定义:给定一种语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 类型:行为类模式 类图: 解释器模式是一个比较少用的模式,本人之前也没有用过这个模式.下面我们就来一起看一下解释器模式. 解释器模式的结构 抽象解释器:声明一个所有具体表达式都要实现的抽象接口(或者抽象类),接口中主要是一个interpret()方法,称为解释操作.具体解释任务由它的各个实现类来完成,具体的解释器分别由终结符解释器TerminalExpr

  • Java设计模式编程之解释器模式的简单讲解

    0.解释器(Interpreter)模式定义 : 给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中句子. 属于行为型模式. 解释器模式在实际的系统开发中使用的非常少,因为它会引起效率.性能以及维护等问题. 解释器模式的通用类图如图所示. 1.解释器模式的优点 解释器是一个简单语法分析工具,它最显著的优点就是扩展性,修改语法规则只要修改相应的非终结符表达式就可以了,若扩展语法,则只要增加非终结符类就可以了. 2.解释器模式的缺点 解释器模式会引起类膨胀:每个语

  • JAVA设计模式之解释器模式详解

    在阎宏博士的<JAVA与模式>一书中开头是这样描述解释器(Interpreter)模式的: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 解释器模式的结构 下面就以一个示意性的系统为例,讨论解释器模式的结构.系统的结构图如下所示: 模式所涉及的角色如下所示: (1)抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口.这个接口主要是一个interpre

随机推荐