解释器是一种用的比较少的行为模式,其提供了一种解释语言的语法,或者表达式的方式。该模式定义了一个表达式的接口
案例(3乘7乘5除以3)
- 抽象接口
/**
* 抽象接口
*/
public interface Node {
int interpret();
}
- 非终结符抽象接口
public abstract class SymbolNode implements Node {
protected Node left;
protected Node right;
public SymbolNode(Node left, Node right) {
this.left = left;
this.right = right;
}
}
- 终结符
*终结符
*/
public class ValueNode implements Node{
private int value;
public ValueNode(int value) {
this.value = value;
}
@Override
public int interpret() {
return value;
}
}
- 具体的计算操作交由子类去实现
//乘法的计算
public class MulNode extends SymbolNode {
public MulNode(Node left, Node right) {
super(left, right);
}
/**
* 计算方法(乘法)
* @return
*/
@Override
public int interpret() {
return left.interpret()*right.interpret();
}
}
//除法计算
public class DivNode extends SymbolNode{
public DivNode(Node left, Node right) {
super(left, right);
}
/**
* 计算方法(除法)
* @return
*/
@Override
public int interpret() {
return left.interpret()/right.interpret();
}
}
- 计算的过程
public class Caculator {
public int build(String num){
Node left=null;
Node right=null;
Node lastNode=null;
String[] statemnts=num.split(" ");
for(int i=0;i<statemnts.length;i++){
if("*".equalsIgnoreCase(statemnts[i])){//乘法
left=lastNode;
int val=Integer.parseInt(statemnts[++i]);
right=new ValueNode(val);
lastNode=new MulNode(left,right);
}else if("/".equalsIgnoreCase(statemnts[i])){//除法
left=lastNode;
int val=Integer.parseInt(statemnts[++i]);
right=new ValueNode(val);
lastNode=new DivNode(left,right);
}else if("%".equalsIgnoreCase(statemnts[i])){
left=lastNode;
int val=Integer.parseInt(statemnts[++i]);
right=new ValueNode(val);
lastNode=new ModeNode(left,right);
} else {
lastNode=new ValueNode(Integer.parseInt(statemnts[i]));
}
}
return lastNode.interpret();
}
}
- 客户端的调用
String content="3 * 5 * 7 / 3 % 30";
Caculator caculator=new Caculator();
int num=caculator.build(content);
System.out.print("最后的结果为:"+num);
- 结果
最后的结果为:5
- 总结:
应用场景:
1. 简单的语言需要解释执行而且可以将该语言中的语句表示一个抽象的语法树
2. 对于某个特定的领域出现的不断重复的问题,可以转换成一种语法规则下的语句
** 优缺点:**
优点: 每个语法都要产生一个非终结符表达式,语法规则比较复杂时,就可能产生大量的类文件,为维护带来了非常多的麻烦。
缺点:
1. 解释器模式采用递归调用方法 每个非终结符表达式只关心与自己有关的表达式,每个表达式需要知道最终的结果,必须一层一层地剥茧,无论是面向过程的语言还是面向对象的语言,递归都是在必要条件下使用的,它导致调试非常复杂。想想看,如果要排查一个语法错误,我们是不是要一个一个断点的调试下去,直到最小的语法单元。
2. 解释器模式由于使用了大量的循环和递归,效率是个不容忽视的问题,特别是用于解析复杂、冗长的语法时,效率是难以忍受的。
最后:
解释器模式在实际的开发中使用的非常少,因为它会引起效率、性能以及维护等问题,一般在大中型的框架型项目能够找到它的身影,比如一些数据分析工具、报表设计工具、科学计算工具等等,若你确实遇到“一种特定类型的问题发生的频率足够高”的情况,准备使用解释器模式时,可以考虑一下Expression4J、MESP(Math Expression String Parser)、Jep等开源的解析工具包