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

定义看起来是非常晦涩。简单来讲,解释器模式通常用于处理特定格式的问题表示,通过定义解释器,能够解释该问题问题表示。例如我们工作过程中遇到的公式计算,公式可以看做是一种特定的问题表示,它具有通用性,正确的公式就应该被正确解析。如公式a+b+c,解释器模式就是要能够处理形如此种的文法,且能够提供相当的扩展性,如支持*,/功能等。

解释器在项目中使用较少,它多用于框架和工具类的开发,类图如下:

  • AbstractExpression 抽象解释器

具体的解释任务由各个实现类完成,具体的解释器分别由TerminalExpression和NonterminalExpression完成。

  • TerminalExpression终结符表达式

实现与文法中的元素相关联的解释操作,通常一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。具体到我们例子就是VarExpression类,表达式中的每个终结符都在堆栈中产生了一个VarExpression对象。

  • NonterminalExpression 非终结符表达式

文法中的每条规则对应于一个非终结表达式,具体到我们的例子就是加减法规则分别对应到AddExpression和SubExpression两个类。非终结符表达式根据逻辑的复杂程度而增加,原则上每个文法规则都对应一个非终结符表达式。

  • Context 环境角色

具体到我们的例子中是采用HashMap代替

优点:

解释器模式的最突出的优点在于其扩展性,修改语法时只要修改相应的解释器就行了,扩展也非常容易,新增解释器即可。

缺点:

解释器会引起类膨胀,如果语法不断扩展,我们必须新增解释器,这样无可避免的导致类的膨胀;另外,解释器模式使用递归计算,这必然导致效率低下。

最佳实践:

解释器模式在实际使用中非常少,因其会导致性能和维护问题,一般它只会出现在数据分析报表设计等使用场景。对于平时的应用时,可以考虑已有的Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包,避免自己开发。

下面给出一个通过解释器实现四则运算的例子(http://www.cnblogs.com/cbf4life/archive/2009/12/17/1626125.html)

抽象表达式类:提供统一的接口

package com.inspur.jiyq.designpattern.interpreter;

import java.util.Map;

public abstract class Expression {
//解析公式和数值,其中var中的key值是是公式中的参数,value值是具体的数字
public abstract int interpreter(Map<String, Integer> var);
}

  抽象符号表达式类:

package com.inspur.jiyq.designpattern.interpreter;

public abstract class SymbolExpression extends Expression{
protected Expression left;
protected Expression right; //所有解析公式应该只关心自己左右两个表达式的结果
public SymbolExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
}

  加法解析器:

package com.inspur.jiyq.designpattern.interpreter;

import java.util.Map;

public class AddExpression extends SymbolExpression {

	public AddExpression(Expression left, Expression right) {
super(left, right);
} @Override
public int interpreter(Map<String, Integer> var) {
return super.left.interpreter(var) + super.right.interpreter(var);
} }

  减法解析器:

package com.inspur.jiyq.designpattern.interpreter;

import java.util.Map;

public class SubExpression extends SymbolExpression {

	public SubExpression(Expression left, Expression right) {
super(left, right);
} @Override
public int interpreter(Map<String, Integer> var) {
return super.left.interpreter(var) - super.right.interpreter(var);
} }

  变量解析器:

package com.inspur.jiyq.designpattern.interpreter;

import java.util.Map;

public class VarExpression extends Expression{
private String key; public VarExpression(String key)
{
this.key = key;
} @Override
public int interpreter(Map<String, Integer> var) {
return var.get(this.key);
}
}

  解析器封装类:(实现运算逻辑)

package com.inspur.jiyq.designpattern.interpreter;

import java.util.Map;
import java.util.Stack; public class Calculator {
// 定义的表达式
private Expression expression; // 构造函数传参并解析
public Calculator(String expStr) {
// 定义一个堆栈,安排运算的先后顺序
Stack<Expression> stack = new Stack<Expression>(); // 表达式拆分为字符数组
char[] charArray = expStr.toCharArray(); // 运算
Expression left = null;
Expression right = null; for (int i = 0; i < charArray.length; i++) {
switch (charArray[i]) {
case '+':// 加法
// 加法结果放到堆栈中
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new AddExpression(left, right));
break;
case '-'://公式中的变量
left = stack.pop();
right = new VarExpression(String.valueOf(charArray[++i]));
stack.push(new SubExpression(left, right));
break;
default:
stack.push(new VarExpression(String.valueOf(charArray[i])));
}
}
this.expression = stack.pop();
} //开始运算
public int run(Map<String, Integer> var)
{
return this.expression.interpreter(var);
}
}

  驱动测试类:

package com.inspur.jiyq.designpattern.interpreter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map; public class Client {
// 运行四则运算
public static void main(String[] args) throws IOException {
String expStr = getExpStr(); // 赋值
Map<String, Integer> var = getValue(expStr);
Calculator cal = new Calculator(expStr);
System.out.println("运算结果为:" + expStr + "=" + cal.run(var));
} public static String getExpStr() throws IOException {
System.out.println("请输入表达式:"); return (new BufferedReader(new InputStreamReader(System.in)))
.readLine();
} // 获得值映射
public static Map<String, Integer> getValue(String exprStr)
throws IOException {
Map<String, Integer> map = new HashMap<String, Integer>();
// 解析有几个参数要传递
for (char ch : exprStr.toCharArray()) {
if (ch != '+' && ch != '-') { // 解决重复参数的问题
if (!map.containsKey(String.valueOf(ch))) {
System.out.print("请输入" + ch + "的值:"); String in = (new BufferedReader(new InputStreamReader(
System.in))).readLine(); map.put(String.valueOf(ch), Integer.valueOf(in));
}
}
}
return map;
}
}

  

设计模式 - interpreter的更多相关文章

  1. 设计模式のInterpreter Patern(解释器模式)----行为模式

    一.问题产生背景 有一句话“小明和小龙是好朋友”,我想分析其中谁是人,我想分析他们的关系等多种需求,那么我们应该如何处理,如果为每一个关系都进行判断?显然不合适,我们可以将二者的关系进行抽象处理,然后 ...

  2. 设计模式-Interpreter(行为模式) 使用解释器给用户提供一个一门定义语言的语法表示的解释器,通过该解释器解释语言中的句子。

    //以下代码来源: 设计模式精解-GoF 23种设计模式解析附C++实现源码 //Context.h #pragma once class Context { public: Context(); ~ ...

  3. Java 设计模式实现 不错的引用

    这段时间有兴趣重新温习一下设计模式在Java中的实现,碰巧看到一个不错的设计模式总结,这里引用一下作为参考. 创建型模式: JAVA设计模式-Singleton JAVA设计模式-Factory JA ...

  4. [php]php设计模式 (总结)

    转载自[php]php设计模式 (总结) 传统的23种模式(没有区分简单工厂与抽象工厂) http://www.cnblogs.com/bluefrog/archive/2011/01/04/1925 ...

  5. [转][osg]探究osg中的程序设计模式【目录】

    作者:3wwang 原文接连:http://www.3wwang.cn/html/article_104.html 前序 探究osg中的程序设计模式---开篇 探究osg中的程序设计模式---创造性模 ...

  6. 《PHP设计模式大全》系列分享专栏

    <PHP设计模式大全>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/201739.html 文章 php设计模式介绍之编程惯用法第 ...

  7. 设计模式之美:Interpreter(解释器)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Interpreter 模式结构样式代码. 实现方式(二):解释波兰表达式(Polish Notation). 意图 给定一个语 ...

  8. 深入浅出设计模式——解释器模式(Interpreter Pattern)

    模式动机 如果在系统中某一特定类型的问题发生的频率很高,此时可以考虑将这些问题的实例表述为一个语言中的句子,因此可以构建一个解释器,该解释器通过解释这些句子来解决这些问题.解释器模式描述了如何构成一个 ...

  9. [设计模式] 15 解释器模式 Interpreter

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对解释器模式是这样说的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.如果一种特定类 ...

随机推荐

  1. PHP中CURL技术模拟登陆抓取网站信息,用与微信公众平台成绩查询

    伴随微信的红火,微信公众平台成为许多开发者的下一个目标.笔者本身对于这种新鲜事物没有如此多的吸引力.但是最近有朋友帮忙开发微信公众平台中一个成绩查询的功能.于是便在空余时间研究了一番. 主要的实现步骤 ...

  2. web一次请求的流程

    1.客户端(浏览器输入网址)请求 2.发送http协议到web服务器(nginx),检测请求类别,如果时纯静态页面,则返响应返回给客户端. 3.如果有动态脚本(php语法)启动fastcgi进程,用解 ...

  3. ajax中的post方法中回调函数不执行的问题

    前一段时间接触了JQuery Ajax中的.post()方法和.get()方法,感觉到ajax的简洁和强大,当用到.post()方法时,去W3上查找相关的使用方法,感觉十分简单,用法很明了,然后,直接 ...

  4. 奖学金评分系统(系统分析与设计版与Delphi实现代码)

    一.系统规划 1.1 项目背景介绍 在奖学金评比过程中,学生综合测评是学校普遍采用的评比手段.对学生实施综合素质测评的目的在于正确评价学生的综合素质,为评奖学金提供依据,实现学生教育管理工作的标准化. ...

  5. [转]java gridbag 说明

    gridx = 2; // X2 gridy = 0; // Y0 gridwidth = 1; // 横占一个单元格 gridheight = 1; // 列占一个单元格 weightx = 0.0 ...

  6. ENVI栅格文件增强后将LUT保存完输出img图像进行分类

    ENVI栅格文件储存 图像原始的DN(Digital Number)值记录图像的光谱信息,不能轻易更改。在窗口中显示的一般是经过拉伸等增强处理的LUT上的灰度值,在保存文件时,就有不同的方式。 1.  ...

  7. iOS 进阶 第二天(0324)

    0324 创建transform transform 是形变属性. 如下图: 如果按照上面的方法来创建的话是这样解释:是相对初始状态来说的,不会在变化后的基础上进行形变.如果要持续变化就要自己去不断改 ...

  8. C# send mail with outlook and word mailmerge

    http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.document_members(v=office.15). ...

  9. swift基础--字符串

    (1)遍历 (2)长度 (3)拼接 (4)插值 (5)大小写 (6)trim (7)split ……等等 var a = "你好" var b = String() a.isEmp ...

  10. Java连接redis的使用示例

    在多线程下使用Jedis 在不同的线程中使用相同的Jedis实例会发生奇怪的错误.但是创建太多的实现也不好因为这意味着会建立很多sokcet连接,也会导致奇怪的错误发生.单一Jedis实例不是线程安全 ...