概念:

  Interpreter模式也叫解释器模式,是行为模式之一,它是一种特殊的设计模式,它建立一个解释器,对于特定的计算机程序设计语言,用来解释预先定义的文法。简单地说,Interpreter模式是一种简单的语法解释器构架。 

  解释器模式应用场景

  当有一个语言需要解释执行, 并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

    1、该文法简单,对于复杂的文法, 文法的类层次变得庞大而无法管理。此时语法分析程序生成器这样的工具是更好的选择。它们无需构建抽象语法树即可解释表达式, 这样可以节省空间而且还可能节省时间。

    2、效率不是一个关键问题,最高效的解释器通常不是通过直接解释语法分析树实现的, 而是首先将它们转换成另一种形式。例如,正则表达式通常被转换成状态机。但即使在这种情况下, 转换器仍可用解释器模式实现, 该模式仍是有用的。

  结构图

  解释器模式的角色和职责

  1、Context:解释器上下文环境类。用来存储解释器的上下文环境,比如需要解释的文法等,简单来说,它的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,给R1赋值100,给R2赋值200,这些信息需要存放到环境中。

  2、AbstractExpression:解释器抽象类。抽象表达式,声明一个所有的具体表达式都需要实现的抽象接口;这个接口主要是一个interpret()方法,称做解释操作。

  3、Terminal Expression:终结符表达式,解释器具体实现类,实现了抽象表达式所要求的接口;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如公式R=R1+R2,R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。

  4、Nonterminal Expression:非终结符表达式,解释器具体实现类,文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式。

  5、Client:客户端,指的是使用解释器的客户端,通常在这里将按照语言的语法做的表达式转换成使用解释器对象描述的抽象语法树,然后调用解释操作。

  举一个计算器的例子

  首先,新建一个Context,通过一个map来存储上下文信息

 /*
* 解释器上下文环境类
*/
public class Context {
private Map<Character, Double> variable; public Map<Character, Double> getVariable() {
if (this.variable == null)
{
this.variable = new HashMap<Character, Double>();
}
return this.variable;
} //返回结果
public void setVariable(Map<Character, Double> variable) {
this.variable = variable;
}
}

  再新建AbstractExpression

 /*
* 抽象表达式
*/
public abstract class Expression {
public abstract double Interpret(Context context);
}

  新建Terminal Expression

 /*
* 变量,终结符表达式
*/
public class VariableExpression extends Expression {
private char key; public VariableExpression(char key)
{
this.key = key;
} @Override
public double Interpret(Context context) {
return context.getVariable().get(key);
}
}

  再新建Nonterminal Expression,因为这其中包含许多不同的实现功能,比如加减乘除,所以我们先新建一个抽象类,再新建不同的实现类

  抽象运算符号解析器

 /*
* 操作符,非终结符表达式
*/
public abstract class OperatorExpression extends Expression {
protected Expression left;
protected Expression right; public OperatorExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
}

  具体的解析器

 /*
* 加法解析器
*/
public class AddExpression extends OperatorExpression { public AddExpression(Expression left, Expression right) {
super(left, right);
} @Override
public double Interpret(Context context) {
return this.left.Interpret(context) + this.right.Interpret(context);
}
}
 /*
* 减法解析器
*/
public class SubExpression extends OperatorExpression { public SubExpression(Expression left, Expression right) {
super(left, right);
} @Override
public double Interpret(Context context) {
return this.left.Interpret(context) - this.right.Interpret(context);
}
}
 /*
* 乘法解析器
*/
public class MulExpression extends OperatorExpression { public MulExpression(Expression left, Expression right) {
super(left, right);
} @Override
public double Interpret(Context context) {
return this.left.Interpret(context) * this.right.Interpret(context);
}
}
 /*
* 除法解析器
*/
public class DivExpression extends OperatorExpression { public DivExpression(Expression left, Expression right) {
super(left, right);
} @Override
public double Interpret(Context context) {
return this.left.Interpret(context) / this.right.Interpret(context);
}
}

  接下来,新建一个解析器封装类

  解析器封装类,这个类是根据迪米特法则进行封装,他并不是解释器模式的组成部分,目的是让Client只与功能模块打交道,不涉及到具体的实现,相当于Facade(外观模式)

 public class Calculator {
private String expression;
private Context context; public Calculator(String expression)
{
this.expression = expression;
this.context = new Context();
} public double Calculate()
{
char[] vars = this.expression.toCharArray();
for(char c : vars){
if (c == '+' || c == '-' || c == '*' || c == '/')
{
continue;
}
if (!this.context.getVariable().containsKey(c))
{
System.out.println("请输入一个数字:");
System.out.print(c+"=");
Scanner sn = new Scanner(System.in);
String readLine = sn.next();
this.context.getVariable().put(c, Double.parseDouble(readLine));
}
}
Expression left = new VariableExpression(vars[0]);
Expression right = null;
Stack<Expression> stack = new Stack<Expression>();
stack.push(left);
for (int i = 1; i < vars.length; i += 2)
{
left = stack.pop();
right = new VariableExpression(vars[i + 1]);
switch (vars[i])
{
case '+':
stack.push(new AddExpression(left, right));
break;
case '-':
stack.push(new SubExpression(left, right));
break;
case '*':
stack.push(new MulExpression(left, right));
break;
case '/':
stack.push(new DivExpression(left, right));
break;
}
}
double value = stack.pop().Interpret(this.context);
stack.clear();
return value;
}
}

  最后,是客户端,解释器的使用者

 //Client客户端
public class Client {
public static void main(String[] args) {
Calculator c = new Calculator("a*b/c");
System.out.println("结果等于" + c.Calculate());
}
}

  运行结果:

  

  优点: 1、可扩展性比较好,灵活。 2、增加了新的解释表达式的方式。 3、易于实现简单文法。

  缺点: 1、可利用场景比较少。 2、对于复杂的文法比较难维护。 3、解释器模式会引起类膨胀。 4、解释器模式采用递归调用方法。

java设计模式-----16、解释器模式的更多相关文章

  1. 折腾Java设计模式之解释器模式

    解释器模式 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 意图 给定一个语言,定义它的文法表 ...

  2. JAVA设计模式之解释器模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述解释器(Interpreter)模式的: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个 ...

  3. 20.java设计模式之解释器模式

    基本需求 实现四则运算,如计算a+b-c+d的值 先输入表达式的形式,如a+b-c+d,要求表达式正确 再分别输出a,b,c,d的值 最后求出结果 传统方案 编写一个方法,接收表达式的形式,根据用户输 ...

  4. 简单的介绍一下Java设计模式:解释器模式

    目录 定义 意图 主要解决问题 优缺点 结构 示例 适用情况 定义 解释器模式是类的行为型模式,给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器,客户端可以使用这个解释器来 ...

  5. Java设计模式之builder模式

    Java设计模式之builder模式 今天学mybatis的时候,知道了SQLSessionFactory使用的是builder模式来生成的.再次整理一下什么是builder模式以及应用场景. 1. ...

  6. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  7. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  8. 乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern)

    原文:乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern) 作 ...

  9. JAVA设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...

  10. 折腾Java设计模式之建造者模式

    博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...

随机推荐

  1. (转)为什么要重写 hashcode 和 equals 方法?

    作者丨hsm_computer cnblogs.com/JavaArchitect/p/10474448.html 我在面试Java初级开发的时候,经常会问:你有没有重写过hashcode方法?不少候 ...

  2. Java并发工具类之并发数控制神器Semaphore

    Semaphore(信号量)使用来控制通知访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源. 我们可以这么理解Semaphore,比如一个厕所只有6个坑,同时只能满足6个人上厕所( ...

  3. java验证身份证合理性

    package com.tiantian.util; import java.util.Calendar;import java.util.HashMap;import java.util.Map;i ...

  4. php引用使用不恰当而产生问题的地方

    php变量的引用,如果使用的恰当,会带来效率的提升,相反,效率下降 $array = range(, ); $ref =& $array; var_dump(count($array)); / ...

  5. 53.storm简介

    一.简介 1.storm是twitter开源的一个分布式的实时计算系统,用于数据实时分析,持续计算,分布式RPC等等. 官网地址:http://storm-project.net 源码地址:https ...

  6. UML入门 之 交互图 -- 时序图 协作图详解

    作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/17927131 动态图概念 : 从静态图中抽取瞬间值的变化描 ...

  7. J07-Java IO流总结七 《 InputStreamReader和OutputStreamWriter 》

    前面在介绍FileReader和FileWriter的时候有说到,FileReader的读取字符功能,以及FileWriter的写出字符的功能,都不是它们自己实现的,而是,它们分别继承了InputSt ...

  8. 剑指offer四十二之和为S的两个数字

    一.题目 输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的. 二.思路 数列满足递增,设两个头尾两个指针i和j,若ai + ...

  9. CountDownTimer倒计时器的使用

    以前好多倒计时的需求都需要自己去写,今天发现android 原来自带了倒计时的类CountDownTimer,和适合用于发送短信 ,等待验证码的情况 代码展示了在一个TextView进行60S的倒计时 ...

  10. java.lang.ArithmeticException: Rounding necessary

    这个错误就是精度丢失问题 https://blog.csdn.net/qq496013218/article/details/70792655