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. mac OS X下PhpStorm+MAMP PRO+Xdebug+FireFox集成开发和断点调试环境配置

    一.环境及软件 1.macbook pro 2.Phpstorm 3.MAMP PRO 4.FireFox 二.环境搭建 1.PhpStorm导入项目 下载PhpStorm并安装,网上随便找个注册码即 ...

  2. YII千万级PV架构经验分享--俯瞰篇--业务扩展演变

    hello,大家好,我是方少,世上不如意事十有八九吧,即使你感到很满意,也有人感觉太差了,总得感觉我们技术人员都是一个人在战斗,感情却是最深的,一起吃过苦才难忘吧.娇妻艳女,你失意了会和你一起吃苦吗? ...

  3. Spark小课堂Week6 启动日志详解

    Spark小课堂Week6 启动日志详解 作为分布式系统,Spark程序是非常难以使用传统方法来进行调试的,所以我们主要的武器是日志,今天会对启动日志进行一下详解. 日志详解 今天主要遍历下Strea ...

  4. scrapy-redis使用详解

    描述: 1.使用两台机器,一台是win10,一台是centos7,分别在两台机器上部署scrapy来进行分布式抓取一个网站 2.centos7的ip地址为192.168.1.112,用来作为redis ...

  5. Security log is full,only administrator can log on to fix the problem(安全日志满了)

    When you login the system and see this error  “Security log on this system is full,only administrato ...

  6. 1020. Tree Traversals (序列建树)

    Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and i ...

  7. 各个浏览器下实现Ajax的JS

    var xmlhttpget; try {     // Firefox, Opera 8.0+, Safari     xmlhttpget = new window.XMLHttpRequest( ...

  8. CocoaPods - 在 Mac 中的生与死

    1. 集成 Cocoapod: 1.1 安装 ruby环境 mac 系统默认有 Ruby 环境, 通过 $ ruby -v 可以查看当前的 Ruby 版本.  如果 Ruby 版本过低可以通过 rvm ...

  9. ExtJS4.2学习(六)表格分页与通过后台脚本获得分页数据

    鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-11-12/175.html --------------- ...

  10. 团体程序设计天梯赛-练习集L2-010. 排座位

    L2-010. 排座位 时间限制 150 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位. ...