当前位置: 首页 > 科技观察

设计模式系列—解释器模式

时间:2023-03-19 15:34:33 科技观察

本文将和大家一起了解解??释器模式。模式定义为分析对象定义了一种语言,并定义了该语言的语法表示,然后设计了一个解析器来解释该语言中的句子。换句话说,使用编译语言来分析应用程序中的示例。这种模式实现了一个用于解释特定上下文的语法表达式处理的接口。这里提到的语法和句子的概念和编译原理中描述的是一样的。“语法”是指语言的语法规则,“句子”是语言集合的元素。比如中文有很多句子,“我是中国人”就是其中之一,可以用句法树来形象地描述语言中的句子。模式的结构和实现解释器模式常用于简单语言的编译或分析。要想掌握它的结构和实现,首先要了解编译原理中的“语法、句子、句法树”等相关概念。语法语法是用于描述语言语法结构的正式规则。没有规则,比如有人认为完美爱情的标准是“相互吸引,彼此投入,双方都没有恋爱经验”。虽然最后一个标准比较严格,但是凡事都要有规矩,语言也是一样。无论是机器语言还是自然语言,都有自己的语法规则。例如,汉语中“句子”的语法如下。::=::=|::=::=|<代词>你|“>”括起来的是非终结符,不括起来的是终结符。句子句子是语言的基本单位,是语言集合的一个元素。它由终结符号组成,可以从“语法”中推导出来。比如上面的文法可以推导出“我是大学生”,所以是一个句子。语法树语法树是句子结构的树状表示,表示句子的推导结果,有利于理解句子的语法结构层次。下图是“我是大学生”的语法树。解释器模式的结构类似于组合模式,但它包含的元素比组合模式多,组合模式是对象结构模式,而解释器模式是类行为模式。模式实现解释器模式的实现关键是定义语法规则,设计终端类和非终端类,绘制结构图,必要时构建语法树。代码结构如下:packagecom.niuh.designpattern.interpreter.v1;/**

*解释器模式*

*/publicclassInterpreterPattern{}//抽象表达式类interfaceAbstractExpression{publicObjectinterpret(Stringinfo);//解释器方法}//终结表达式classClassTerminalExpressionimplementsAbstractExpression{publicObjectinterpret(Stringinfo){//终端表达式的处理returnnull;}}//NonterminalExpressionclassNonterminalExpressionimplementsAbstractExpression{privateAbstractExpressionexp1;privateAbstractExpressionexp2;publicObjectinterpret(Stringinfo){//非终端表达式的处理returnnull;}}//环境类classContext{privateAbstractExpressionexp;publicContext(){//数据初始化}publicvoidoperation(Stringinfo){//调用相关表达式类的解释方法}}解决构造解释器对一些固定语法的句子进行解释的问题。模式组成示例说明示例概述使用解释器模式设计一个北京公交卡读卡器程序。说明:如果北京公交读卡器可以识别乘客身份,如果“海淀区”或“朝阳区”的“老人”、“妇女”、“儿童”可以免费乘车,其他人将被扣2元每乘。分析:本例采用“解释器模式”设计更为合适。首先,其语法规则设计如下。::=::=HaidianDistrict|朝阳区::=elderly|women|childrenof::=那么,根据语法规则,如下下面按步骤设计公交卡读卡器程序的类图。第一步:定义一个抽象表达式(Expression)接口,其中包含解释方法interpret(Stringinfo)。//抽象表达式类interfaceExpression{publicbooleaninterpret(Stringinfo);}第二步:定义一个终端表达式(TerminalExpression)类,它使用一个集合(Set)类来存储满足条件的城市或人物,实现抽象表达式接口中的解释方法interpret(Stringinfo)用于判断分析的字符串是否为集合中的终结符号。classTerminalExpressionimplementsExpression{privateSetset=newHashSet();publicTerminalExpression(String[]data){for(inti=0;ijepjep2.24我们来看一个案例:packagecom.niuh.designpattern.interpreter.v3;importorg.nfunk.jep.JEP;/***

*JepDemo*

*/publicclassJepDemo{publicstaticvoidmain(String[]args){JEPjep=newJEP();//一个数学表达式Stringexp="((a+b)*(c+b))/(c+a)/b";//给变量赋值jep.addVariable("a",10);jep.addVariable("b",10);jep.addVariable("c",10);try{//执行jep.parseExpression(exp);Objectresult=jep.getValueAsObject();System.out.println("计算结果:"+result);}catch(Throwablee){System.out.println("Anerororoccured:"+e.getMessage());}}}程序运行结果如下:计算结果:2.0源码应用SpelExpressionParser在解释器模式下的应用分析类图分析在下面的类图中,Expression是一个接口,相当于我们解释器模式下的一个非终结符表达式,ExpressionParser相当于终端字符表达式。根据不同的Parser对象,返回不同的Expression对象。部分部分源码源码源码表达式接口//抽象抽象的非非表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式表达式//publicInterFaceEppression{objectValue()(this.compiledAst!=null){try{TypedValuecontextRoot=evaluationContext==null?null:evaluationContext.getRootObject();returnthis.compiledAst.getValue(contextRoot==null?null:contextRoot.getValue(),evaluationContext);}catch(Throwableex){//Ifrunninginmixedmode,reverttointerpretedif(this.configuration.getCompilerMode()==SpelCompilerMode.MIXED){this.interpretedCount=0;this.compiledAst=null;}else{//RunninginSpelCompilerMode.immediatemode-propagateexceptiontocallerthrownewSpelEvaluationException(ex,SpelMessage).EXCEPTION_RUNNING_COMPILED_EXPRESSION);}}}ExpressionStateexpressionState=newExpressionState(getEvaluationContext(),this.configuration);result=this.ast.getValue(expressionState);checkCompile(expressionState);returnresult;}}CompositeStringExpression//具体的非最终符号表达式publicclassCompositeStringExpressionimplementsExpression{@OverridepublicStringgetValue()throwsEvaluationException{StringBuildersb =newStringBuilder();for(Expressionexpression:this.expressions){Stringvalue=expression.getValue(String.class);if(value!=null){sb.append(value);}}returnsb.toString();}}ExpressionParser接口publicinterfaceExpressionParser{//解析表达式ExpressionparseExpression(StringexpressionString)throwsParseException;ExpressionparseExpression(StringexpressionString,ParserContextcontext)throwsParseException;}TemplateAwareExpressionParser类publicabstractclassTemplateAwareExpressionParserimplementsExpressionParser{@OverridepublicExpressionparseExpression(StringexpressionString)throwsParseException{returnparseExpression(expressionString,NON_TEMPLATE_PARSER_CONTEXT);}//根据不同的parser返回不同的Expression对象@OverridepublicExpressionparseExpression(StringexpressionString,ParserContextcontext)throwsParseException{if(context==null){context=NON_TEMPLATE_PARSER_CONTEXT;}if(context.isTemplate()){returnparseTemplate(expressionString,context);}else{returndoParseExpression(expressionString,context);}}privateExpressionparseTemplate(StringexpressionString,ParserContextcontext)throwsParseException{if(expressionString.length()==0){returnnewLiteralExpression("");}Expression[]expressions=parseExpressions(expressionString,context);if(expressions.length==1){returnexpressions[0];}else{returnnewCompositeStringExpression(expressionString,expressions);}}//抽象的,由子类去实现protectedabstractExpressiondoParseExpression(StringexpressionString,ParserContextcontext)throwsParseException;}SpelExpressionParser类publicclassSpelExpressionParserextendsTemplateAwareExpressionParser{@OverrideprotectedSpelExpressiondoParseExpression(StringexpressionString,ParserContextcontext)throwsParseException{//这里返回了一个InternalSpelExpressionParser,returnnewInternalSpelExpressionParser(this.configuration).doParseExpression(expressionString,context);}}InternalSpelExpressionParser类classInternalSpelExpressionParserextendsTemplateAwareExpressionParser{@OverrideprotectedSpelExpressiondoParseExpression(StringexpressionString,ParserContextcontext)throwsParseException{try{this.expressionString=expressionString;Tokenizertokenizer=newTokenizer(expressionString);tokenizer.process();this.tokenStream=tokenizer.getTokens();this.tokenStreamLength=this.tokenStream.size();this.tokenStreamPointer=0;this.constructedNodes.clear();SpelNodeImplast=eatExpression();if(moreTokens()){thrownewSpelParseException(peekToken().startPos,SpelMessage.MORE_INPUT,toString(nextToken()));}Assert.isTrue(this.constructedNodes.isEmpty());returnnewSpelExpression(expressionString,ast,this.configuration);}catch(InternalParseExceptionex){throwex.getCause();}}}PS:以上代码提交在Github:https://github.com/Niuh-Study/niuh-designpatterns.git