设计之禅——解释器模式(译文)
时间:2022-07-24
本文章向大家介绍设计之禅——解释器模式(译文),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前言
解释器模式在平时基本上用不到,因此笔者也不打算花太多精力在这上面,但强迫症使然,所以翻译了GeeksForGeeks上面的一篇文章,本文采取意译及注解方式,原文链接Interpreter Pattern
译文
解释器模式是一种行为型模式,它提供一个解析特定语法规则的解释器。
- 该模式包含一个表达式接口,该表达式族用来解析一些特定的语法规则。此模式常用于sql解析、符号解析引擎等。
- 该模式执行于解析表达式上,并且每一个表达式都包含终结符和非终结符。如a + b,a、b即为终结符,+为非终结符;那么解析终结符的解释器即为终结符表达式,解析非终结符的解释器为非终结符表达式。
- 将解释器模式的结构看作树形的话,其终结符表达式就像是组合中的叶子,而非终结符表达式就像是组件一般。
看例子,这里有一个由“+ - 9 8 7”组成的表达式树:
解释器模式的类图:
由图我们可以看到解释器模式包含以下几个角色:
- 抽象表达式:声明一个包含interpreter方法的接口,所有终结符表达式或非终结符表达式需要实现该接口并重写该方法。
- 终结符表达式:重写interpreter方法解析终结符。
- 非终结符表达式:重写interpreter解析非终结符,如“+、-、*、/”等。
- Context上下文:保存全局解释器的信息(原文是用String实现,这里没有全部按照其翻译)。
- 客户端:组装表达式结构,并执行解释器方法interpreter解析表达式。
下面是代码演示简单的四则运算(因原文使用的是String来表现Context,个人感觉不太直观,体现不出Context的作用,因此引用了另一篇博文的例子——设计模式(行为型)之解释器模式(Interpreter Pattern)),首先是表达式族:
// 抽象表达式
public interface Expression {
int interpret(Context context);
}
// 终结符表达式
public class Variable implements Expression {
@Override
public int interpret(Context context) {
// 该表达式呈现的是一个随时可更改值的表达式,因此具体值保存在context中
return context.getValue(this);
}
}
// 字面量值使用该表达式存储
public class Constant implements Expression {
private int value;
public Constant(int value) {
this.value = value;
}
@Override
public int interpret(Context context) {
return value;
}
}
// 非终结符表达式
// 加法解析器
public class AddExpression implements Expression {
private Expression left, right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) + right.interpret(context);
}
}
// 减法解析器
public class SubExpression implements Expression {
Expression left, right;
public SubExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) - right.interpret(context);
}
}
// 乘法解析器
public class MulExpression implements Expression {
private Expression left, right;
public MulExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) * right.interpret(context);
}
}
// 除法解析器
public class DevExpression implements Expression {
private Expression left, right;
public DevExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret(Context context) {
return left.interpret(context) / right.interpret(context);
}
}
然后是Context类:
public class Context {
// 使用Map来存储表达式和值
private Map<Variable, Integer> map = new HashMap<>();
// 将表达式和值存入map
public void putValue(Variable x, Integer y) {
map.put(x, y);
}
// 通过表达式对象获取对应的值
public Integer getValue(Variable x) {
return map.get(x);
}
}
客户端测试:
public static void main(String[] args) {
// 首先创建变量x, y
Variable x = new Variable();
Variable y = new Variable();
// 获取上下文容器,保存变量值
Context context = new Context();
context.putValue(x, 5);
context.putValue(y, 10);
// 创建常量
Expression constant = new Constant(100);
// 计算(x + y) * 100 / x
Expression expression = new DevExpression(new MulExpression(new AddExpression(x, y), constant), x);
int res = expression.interpret(context);
System.out.println(res);
}
通过上面的例子我们可以发现解释器模式的优点如下:
- 每个语法都实现自同一个接口,且独立,因此扩展方便,很容易修改已有规则或是扩展新的规则。
- 实现一个新的语法规则也很容易,因为所有的表达式都实现自同一个接口或继承自同一个抽象类,因此它们彼此之间都具有共通性。
解释器模式的缺点也很明显:
- 每一个语法规则就需要新定义一个类,因此对于一个具有复杂语法的语言,那么解释器模式就非常难以维护。
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Centos8(最小化安装)全新安装Python3.8+pip的方法教程
- 使用 Linux seq 命令生成数字序列(推荐)
- CentOS 7上为PHP5安装suPHP的方法(彭哥)
- Linux修改主机名命令详解
- 在CentOS 7.2上安装SuPHP的详细方法
- centos6-7 yum安装php的方法(推荐)
- Linux修改用户所属组的方法
- centos通过yum安装php的教程
- 树莓派4安装Ubuntu 19.10的教程详解
- Linux系统(CentOS7安装)安装JDK8的教程详解
- Deepin中安装与使用virtualenv的教程
- linux安装jdk并设置环境变量的方法教程(看这一篇够了)
- hadoop基于Linux7的安装配置图文详解
- Linux paste命令的使用方法
- ubuntu下迁移home目录至新的分区教程详解