常用设计模式系列(十五)—解释器模式
常用设计模式系列(十五)—解释器模式
第一节
前言
各位老铁大家好,郑州这两天步入了三伏天,动两步就“汗如雨下”,天气这么热,需要公司及家里都开着空调“续命”,公司到小区那五百米的距离,变成了我上班路上的绊脚石,每次出门都有一种“风萧萧兮易水寒,壮士一去兮不复返”的错觉,每次出个门都是一次挑战,有时候想着,为啥公司楼下的玻璃是透明的,当皮肤与直射的阳光接触的那一瞬间,简直不要太酸爽。
再热的天,再大的太阳,都能被我到手那可怜的工资的“凉凉”消化!步入正题,今天讲解的是类模式下的行为型设计模式第二节——解释器模式,解释器比较常见,在我们的JVM中,有着Java编译器和Java解释器,Java作为高级语言,计算机只能执行机器语言,故Java代码不能够被直接执行,解释器将高级语言一行一行进行解释,让计算机可以执行,这个中间对象负责的工作就是解释器。解释器模式的想法也是从解释器那参考学习过来的。
第二节
解释器模式
解释器模式(Interpreter
Pattern):提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在
SQL 解析、符号处理引擎等。个人理解(Person
Understand):给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子
解释器模式组成:
场景举例:
我们在学习Java程序的时候,肯定学习或转义字符,当使用Java的控制台输出时,遇到“\n”就是换行,遇到“\t”就是缩进,遇到“\”则是转义,那么Java程序在读到我们所写的代码,并将代码解析并执行的过程则就是解释器模式的工作模式。
第三节
代码设计与实现
场景设计:
使用场景模拟完成解释器模式,A公司先要设计一款智能机器人,这个机器人需要指令来指示机器人完成对应的动作,那么当程序设计完成之后,通过输入指令集即可完成对机器人的控制,这个将程序指令集解释并执行的过程就是解释器模式。
场景分析:
先来分析下,机器人可以走,可以跑,跑的话是有距离的,在一个平面上,机器人可以往上下左右四个方向去跑,那么将走和跑及距离进行结合,当一个动作结束需要加另一个动作时,我们可以使用“and”字符完成连接,此时经过分析可以得到如下的分析
表达式(expression):移动方向 移动类型 移动距离
综合表达式(composite):表达式 and 表达式
移动方向(dorection):上(up)、下(down)、左(left)、右(right)
移动类型(action):走(move)、跑(run)
移动距离(distance):数字(单位米)
表达式示例:left run 10 and up move 5(往左跑10并往上移动5)
组成设计:
1.设计抽象表达式AbstractNode2.设计终结符表达式(移动方向类)DrectionNode、移动类型类ActionNode及Distance移动距离类3.设计非终结表达式SentenceNode来完成表达式方向+类型+距离。4.编写环境角色用来解析并解释语义并调用终结表达式和非终结表达式5.编写客户端对语法进行测试
UML图:
代码编写:
1.设计抽象表达式AbstractNode
package com.yang.interpret;/*** @ClassName AbstractNode* @Description 抽象表达式* @Author IT小白架构师之路* @Date 2021/1/19 20:07* @Version 1.0**/
public abstract class AbstractNode {/*** 抽象方法* @return*/public abstract String interpret();
}
2.设计终结符表达式(移动方向类)DrectionNode
package com.yang.interpret;/*** @ClassName DrectionNode* @Description 移动方向类* @Author IT小白架构师之路* @Date 2021/1/19 20:10* @Version 1.0**/
public class DrectionNode extends AbstractNode {//移动方向private String direction;public DrectionNode(String direction){this.direction = direction;}@Overridepublic String interpret() {String result;switch (direction){case "up":result = "向上";break;case "down":result = "向下";break;case "left":result = "向左";break;case "right":result = "向右";break;default:result = "指令错误";break;}return result;}
}
3.设计终结符表达式,移动类型类ActionNode
package com.yang.interpret;/*** @ClassName ActionNode* @Description 移动类型* @Author IT小白架构师之路* @Date 2021/1/19 20:19* @Version 1.0**/
public class ActionNode extends AbstractNode {private String action;public ActionNode(String action){this.action = action;}@Overridepublic String interpret() {String result;switch (action){case "move":result = "走";break;case "run":result = "跑";break;default:result = "指令错误";break;}return result;}
}
4.设计终结符表达式,Distance移动距离类
package com.yang.interpret;/*** @ClassName Distance* @Description 移动距离* @Author IT小白架构师之路* @Date 2021/1/19 20:21* @Version 1.0**/
public class DistanceNode extends AbstractNode {private String distance;public DistanceNode(String distance){this.distance = distance;}@Overridepublic String interpret() {return this.distance+"米";}
}
5.设计非终结表达式SentenceNode来完成衔接
package com.yang.interpret;/*** @ClassName SentenceNode* @Description 动作衔接* @Author IT小白架构师之路* @Date 2021/1/19 20:22* @Version 1.0**/
public class SentenceNode extends AbstractNode{//移动方向private AbstractNode drectionNode;//移动类型private AbstractNode actionNode;//移动距离private AbstractNode distanceNode;public SentenceNode(AbstractNode drectionNode,AbstractNode actionNode,AbstractNode distanceNode){this.drectionNode = drectionNode;this.actionNode = actionNode;this.distanceNode = distanceNode;}@Overridepublic String interpret() {return drectionNode.interpret() + actionNode.interpret() + distanceNode.interpret();}
}
6.设计语言解释器 LanguageHandle
package com.yang.interpret;import java.util.Arrays;
import java.util.List;/*** @ClassName LanguageHandle* @Description 语法解释器* @Author IT小白架构师之路* @Date 2021/1/19 20:28* @Version 1.0**/
public class LanguageHandle {public void handle(String expression){//第一步声明三个表达式//移动方向AbstractNode drectionNode;//移动类型AbstractNode actionNode;//移动距离AbstractNode distanceNode;//组合类AbstractNode sentenceNode;//语法解析,将and进行拆分,解析综合表达式String [] arrays = expression.split(" and ");//拆分为多个表达式List<String> list = Arrays.asList(arrays);for (String temp : list){//根据空格进行拆分具体表达式String [] tempArray = temp.split(" ");//方向String direction = tempArray[0];//类型String action = tempArray[1];//距离String distance = tempArray[2];//开始解析drectionNode = new DrectionNode(direction);actionNode = new ActionNode(action);distanceNode = new DistanceNode(distance);sentenceNode = new SentenceNode(drectionNode,actionNode,distanceNode);//最终结果System.out.println(sentenceNode.interpret());}}
}
7.编写客户端测试
package com.yang.interpret;/*** @ClassName Client* @Description 客户端* @Author IT小白架构师之路* @Date 2021/1/19 20:38* @Version 1.0**/
public class Client {public static void main(String[] args) {String expression = "left run 10 and up move 5 and right run 10";LanguageHandle languageHandle = new LanguageHandle();languageHandle.handle(expression);}
}
8.测试结果
向左跑10米
向上走5米
向右跑10米
第四节
优缺点及适用场景
优点:
1.容易改变处理过程且容易扩展文法,解释器模式使用类来表示语言的文法规则,可以通过继承的机制改变或者扩展文法。
2.每一个规则都可以表示为一个类,所以可以方便的实现一个简单的语言。
3.增加新的解释表达式可通过增加新的终结符表达式或者非终结符表达式类,不需要修改原来的表达式类,符合开闭原则。
缺点:
1.如果出现较为复杂的表达式,此时文法较为复杂,当维护的时候,由于每个规则定义了一个类,如果一个类包含了许多规则,则会增加相同数量的类来做支撑,此时类的数量会变得很多,并且难以管理和维护。
2.执行效率偏低,因为解释器使用的是对字符串的拆分解析,并且使用大量的循环,当语法比较复杂时,速度会变慢。
适用场景:
1.当一个需要解释执行的语言表示为Java抽象语法树时。
2.重复出现的问题可以考虑使用简单的语法进行表达。
3.当一个语言文法比较简单,需要进行解释执行时,文法复杂时,执行效率偏低,不适合
扫描二维码
关注我吧
IT小白架构师之路