Java设计模式学习记录-解释器模式
前言
这次介绍另一个行为模式,解释器模式,都说解释器模式用的少,其实只是我们在日常的开发中用的少,但是一些开源框架中还是能见到它的影子,例如:spring的spEL表达式在解析时就用到了解释器模式,以及mybatis在将SQL语句映射成对象时关系时、还有一些解析正则表达式和解析json等开源工具。
解释器模式
概念介绍
解释器模式是指给定一个使用规定格式和语法的语言,并且建立一个解释器来解释该语言中的句子。解释器本身就是一种按照规定的语法进行解析的方案,但是总体来说也是一种使用频率相对较低但学习难度较大的设计模式。
举例
因为解释器模式用到地方不太多,实在想不到举什么样的例子合适,所以就使用一个简单的来实现一个垒加的功能的例子吧。
具体过程如下:
上下文环境类
@Getter
@Setter
public class Context { /**
* 输入
*/
private String input;
/**
* 结果
*/
private int output; public Context(String input){
this.input = input;
} @Override
public String toString() {
return input + "=" + output;
}
}
抽象表达式类
public abstract class Expression {
Context context;
/**
* 解释一个给定的表达式
* @param context
*/
public abstract void interpret(Context context);
}
垒加类
/**
* 垒加1
*/
public class MinusExpression extends Expression { /**
* 解释一个给定的表达式
*
* @param context
*/
@Override
public void interpret(Context context) { this.context = context;
String input = context.getInput();
int in = Integer.valueOf(input);
context.setOutput(in-1); } @Override
public String toString() {
return "--"+context.getInput()+"="+context.getOutput();
}
}
垒减
/**
* 垒减
*/
public class PlusExpression extends Expression { /**
* 解释一个给定的表达式
*
* @param context
*/
@Override
public void interpret(Context context) { this.context = context;
String input = context.getInput();
int in = Integer.valueOf(input);
context.setOutput(in+1); } @Override
public String toString() {
return "++"+context.getInput()+"="+context.getOutput();
}
}
测试,使用
public class Client {
public static void main(String[] args) {
Context context = new Context("50");
Expression plus = new PlusExpression();
Expression minus = new MinusExpression();
//执行垒加
plus.interpret(context);
System.out.println(plus.toString());
//垒减
minus.interpret(context);
System.out.println(minus.toString());
}
}
运行结果
++50=51
--50=49
通过运算结果可以看出来,表达式通过解释后的结果,++50解释后结果是51,--50解释后结果是49。
解释器模式分析
解释器模式的结构图如下:

解释器类图上的各个角色说明:
Expression(抽象解释器):定义解释方法,具体的解释任务由各个实现类完成,具体的解释器分别由TerminalRxpression和NonterMinalExpression完成。抽象解释器对应上面例子中的Expression类
TerminalExpression(终结符表达式):实现与文法中的元素相关的解释操作,一个解释器模式中只有一个终结符表达式,但有多个实例,对应不同的终结符。上面的代码例子中的PlusExpression和MinusExpression都是这个角色。
NoteTerminalExpression(非终结符表达式):文法中的每条规则对应于一个非终结符表达式。非终结符表达式是根据逻辑的复杂度而增加,原则上每个文法规则都对应一个非终结符表达式。由于上面举得例子比较简单,所以上面的例子中是没有这个角色的。
Context(环境角色):环境类又称为上下文类,它用于存储解释器之外的一些全局信息,通常它临时存储了需要解释的语句。也可以使用集合用来存储要解释的内容。
解释器模式总结
解释器模式的优点
1、易于改变和扩展文法。因为该模式使用类表示文法,所以可以使用继承改变或扩展该文法。
2、每条文法规则都可以是一个类,所以可以很方便的实现一个简单的语言。
3、易于实现文法的定义。在抽象语法树中每一个表达式节点类的实现方式都是相似的,这些类的代码编写都不会特别复杂,还可以通过一些工具自动生成节点类代码。
4、增加新的解释表达式较为方便。如果用户需要增加新的解释表达式只需要对应增加一个新的终结符表达式或非终结符表达式类,原有表达式类代码无须修改,符合“开闭原则”。
解释器模式的缺点
1、对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
2、执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。
适用场景
1、可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。
3、一个语言的文法较为简单。
4、执行效率不是关键问题。【注:高效的解释器通常不是通过直接解释抽象语法树来实现的,而是需要将它们转换成其他形式,使用解释器模式的执行效率并不高。】
想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述。
Java设计模式学习记录-解释器模式的更多相关文章
- Java设计模式学习记录-模板方法模式
前言 模板方法模式,定义一个操作中算法的骨架,而将一些步骤延迟到子类中.使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤. 模板方法模式 概念介绍 模板方法模式,其实是很好理解的,具体 ...
- Java设计模式学习记录-状态模式
前言 状态模式是一种行为模式,用于解决系统中复杂的对象状态转换以及各个状态下的封装等问题.状态模式是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活多变.这样在客户端使 ...
- Java设计模式学习记录-备忘录模式
前言 这次要介绍的是备忘录模式,也是行为模式的一种 .现在人们的智能手机上都会有备忘录这样一个功能,大家也都会用,就是为了记住某件事情,防止以后自己忘记了.那么备忘录模式又是什么样子的呢?是不是和手机 ...
- Java设计模式学习记录-迭代器模式
前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/ ...
- Java设计模式学习记录-命令模式
前言 这次要介绍的是命令模式,这也是一种行为型模式.最近反正没有面试机会我就写博客呗,该投的简历都投了.然后就继续看书,其实看书也会给自己带来成就感,原来以前不明白的东西,书上已经给彻底的介绍清楚了, ...
- Java设计模式学习记录-外观模式
前言 这次要介绍的是外观模式(也称为门面模式),外观模式也属于结构型模式,其实外观模式还是非常好理解的,简单的来讲就是将多个复杂的业务封装成一个方法,在调用此方法时可以不必关系具体执行了哪些业务,而只 ...
- Java设计模式学习记录-桥接模式
前言 这次介绍结构型设计模式中的第二种模式,桥接模式. 使用桥接模式的目的就是为了解耦,松散的耦合更利于扩展,但是会增加相应的代码量和设计难度. 桥接模式 桥接模式是为了将抽象化与实现化解耦,让二者可 ...
- Java设计模式学习记录-代理模式
代理模式 代理模式是常见设计模式的一种,代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起 ...
- Java设计模式学习记录-建造者模式
前言 今天周末,有小雨,正好也不用出门了,那就在家学习吧,经过了两周的面试,拿到了几个offer,但是都不是自己很想去的那种,要么就是几个人的初创小公司,要么就是开发企业内部系统的这种传统开发,感觉这 ...
随机推荐
- UI与开发的必备神器!— iDoc一键适配不同平台尺寸(iDoc201902-2新功能)
一.自动换算不同平台尺寸在一个项目从设计到开发的过程中,为了适配不同设备,一份设计稿,UI需要花大量的时间去制作各种尺寸的切图,耗时耗力. 那有没有一种高效的办法,让UI只需要设计一份设计稿就可以了呢 ...
- 《Linux就该这么学》第七天课程
昨天晚上我找了刘老师决定了报考红帽RHCSA,RHCE认证,我不指望这个认证能给我带来工作上的某些福利,毕竟出去闯靠的是实力外加运气 我只是希望通过这个认证来激励自己! 下面是分享的一些干货! 原创地 ...
- LwIP协议栈接口
协议栈api函数 1.netconn_new //UDP TCP struct netconn*netconn_new(enum netconn_type t) 为新连接申请一个连接结 ...
- 去掉input[type="number"]的默认样式
input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{ -webkit-appearance: none !importa ...
- Codeforces Round #539--1113B - Sasha and Magnetic Machines
https://codeforces.com/contest/1113/problem/B 思想不难,但是在比较大小的时候,我选择了很笨的方法,我用两个数变化之后的差值大小来进行选择,然后最后再进行数 ...
- Spring 使用xml配置aop
1.xml文件需要引入aop命名空间 2.xml内容: <?xml version="1.0" encoding="UTF-8"?> <bea ...
- 利用ArcGIS-Server瓦片制作离线地图包(*.tpk)_详细流程
1.写在前面 本人是综合了好几个资料才最终制作成功,在这个过程中发现网上好多博客写的步骤不是很详细,因此就把自己的详细制作步骤全部分享出来,可以供需要的小伙伴参考. (1)本文档不讨论tpk文件的详细 ...
- 微服务应用新趋势:Service Mesh、AIOps和中台化
微服务技术由于天生支持快速迭代.弹性扩展的特点,使企业能够在不确定性下提升发展速度及抗风险能力,受到了越来越多的关注.当前,云服务商纷纷试水微服务产品,最为典型的,当属推出轻舟微服务平台.剑指整个微服 ...
- vue高级组件之provide / inject
转载:https://blog.csdn.net/Garrettzxd/article/details/81407199 在vue中不同组件通信方式如下 1.父子组件,通过prop 2.非父子组件,通 ...
- Typescript 学习笔记七:泛型
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...