Int(valueAndSymbolList.get(k)));
if (leftExpression == null) {
leftExpression = rightExpression;
}
}
k++;
if (k < valueAndSymbolList.size()) {
rightExpression = new Value(Integer.parseInt(valueAndSymbolList.get(k + 1)));
if (valueAndSymbolList.get(k).equals("+")) {
leftExpression = new Plus(leftExpression, rightExpression);
} else if (valueAndSymbolList.get(k).equals("-")) {
leftExpression = new Minus(leftExpression, rightExpression);
}
k++;
}
}
return leftExpression;
}
通过上面的这个方法,我们就可以直接解析字符串了
总结
解释器模式是用于解析一种“语言”,对于使用频率较高的,模式、公式化的场景,可以考虑使用解释器模式。
比如正则表达式,将“匹配”这一语法,定义为一种语言
浏览器对于HTML的解析,将HTML文档的结构定义为一种语言
我们上面的例子,将加减运算规则定义为一种语言
所以,使用解释器模式要注意“
高频”“
公式”“
格式”这几个关键词
解释器模式将语法规则抽象的表述为类
解释器模式
为自定义语言的设计和实现提供了一种解决方案,它用于定义一组文法规则并通过这组文法规则来解释语言中的句子。
解释器模式非常容易扩展,如果增加新的运算符,比如乘除,只需要增加新的非终结符表达式即可
改变和扩展语言的规则非常灵活
非终结符表达式是由终结符表达式构成,基本上需要借助于嵌套,递归,所以代码本身一般比较简单
像我们上面那样, Plus和Minus 的代码差异很小
如果语言比较复杂,显然,就会需要定义大量的类来处理
解释器模式中
大量的使用了递归嵌套,所以说它的
性能是很有问题的,如果你的系统是性能敏感的,你就更要慎重的使用
据说解释器模式在实际的系统开发中使用得非常少,另外也有一些开源工具
Expression4J、MESP(Math Expression String Parser)、Jep
所以
不要自己实现
另外还需要注意的是,从我们上面的示例代码中可以看得出来
解释器模式的重点在于AbstractExpression、TerminalExpression、NoneTerminalExpression的提取抽象
也就是对于文法规则的映射转换
而至于如何转换为抽象语法树,这是客户端的责任
我们的示例中可以通过new不断地嵌套创建expression对象
也可以通过方法解析抽象语法树,都可以根据实际场景处理
简言之,
解释器模式不关注抽象语法树的创建,仅仅关注解析处理
所以个人看法:
但凡你的问题场景可以抽象为一种语言,也就是有规则、公式,有套路就可以使用解释器模式
不过如果有替代方法,能不用就不用
如果非要用,你也不要自己写
|