解释器模式 解释器模式是类的行为模式,给定一个语言,定义他的文法表示,并且定义一个解释器,客户端可以使用这个解释器来解释这个语言中的句子。一般在现实应用中使用的比较少,毕竟相对来说,我们一般不需要自己定义一套自己的语法来解析。其实相对来说,解释器就相当于大脑,把一句话翻译成可以理解的内容。 解释器模式的示例图 解释器模式包含的角色
抽象表达式角色:声明一个所有具体表达式角色都需要实现或者继承的抽象接口。该接口最主要的是一个interpret()
方法,一般称为解释操作。 终结符表达式角色:实现了抽象表达式角色所要求的接口,主要是interpret()
方法。文法中的每个终结符都有一个具体的终结表达式与之对应,比如一个简单的加法运算a=b+c;在这里面b和c都是终结符,对应的解释b和c的解释器就是终结符表达式。 非终结符表达式角色:文法中每一个规则都需要一个具体的非终结符表达式,一般表示文法中的运算符或者其他关键字,上面的加法运算中"+“就是非终结符。解析”+"的解释器就是一个非终结符表达式。 环境角色:这个角色的任务一般是用来存放文法中各个终结符对应的具体值,比如b,c,我们可以给b赋值100,c赋值为200,这些就需要存放到环境角色中,很多情况下我们使用Map来充当环境角色。
示例代码:(示例代码引用自《JAVA设计模式(22):行为型-解释器模式(Interpreter)》 )
public class Context {
private StringTokenizer stringTokenizer;
private String currentToken;
public Context ( String text) {
stringTokenizer = new StringTokenizer ( text) ;
nextToken ( ) ;
}
public String nextToken ( ) {
if ( stringTokenizer. hasMoreTokens ( ) ) {
currentToken = stringTokenizer. nextToken ( ) ;
} else {
currentToken = null;
}
return currentToken;
}
public String currentToken ( ) {
return currentToken;
}
public void skipToken ( String token) {
if ( ! token. equals ( currentToken) ) {
System. err. println ( "错误提示:" + currentToken + "解释错误!" ) ;
}
nextToken ( ) ;
}
public int currentNumber ( ) {
int number = 0 ;
try {
number = Integer. parseInt ( currentToken) ;
} catch ( NumberFormatException e) {
System. err. println ( "错误提示:" + e) ;
}
return number;
}
}
public abstract class Expression {
abstract void interpreter ( Context text) ;
public abstract void execute ( ) ;
}
public class ExpressionNode extends Expression {
private ArrayList< Expression> list = new ArrayList < Expression> ( ) ;
@Override
void interpreter ( Context text) {
while ( true ) {
if ( text. currentToken ( ) == null) {
break ;
} else if ( text. currentToken ( ) . equals ( "END" ) ) {
text. skipToken ( "END" ) ;
break ;
} else {
Expression commandExpression = new CommandExpression ( ) ;
commandExpression. interpreter ( text) ;
list. add ( commandExpression) ;
}
}
}
@Override
public void execute ( ) {
Iterator iterator = list. iterator ( ) ;
while ( iterator. hasNext ( ) ) {
( ( Expression) iterator. next ( ) ) . execute ( ) ;
}
}
}
public class CommandExpression extends Expression {
private Expression expression;
@Override
void interpreter ( Context text) {
if ( text. currentToken ( ) . equals ( "LOOP" ) ) {
expression = new LoopCommandExpression ( ) ;
expression. interpreter ( text) ;
} else {
expression = new PrimitiveCommandExpression ( ) ;
expression. interpreter ( text) ;
}
}
@Override
public void execute ( ) {
expression. execute ( ) ;
}
}
public class LoopCommandExpression extends Expression {
private int number;
private Expression commandExpression;
@Override
void interpreter ( Context text) {
text. skipToken ( "LOOP" ) ;
number= text. currentNumber ( ) ;
text. nextToken ( ) ;
commandExpression = new ExpressionNode ( ) ;
commandExpression. interpreter ( text) ;
}
@Override
public void execute ( ) {
for ( int i= 0 ; i< number; i++ ) {
commandExpression. execute ( ) ;
}
}
}
public class PrimitiveCommandExpression extends Expression {
private String name;
private String textStr;
@Override
void interpreter ( Context text) {
name = text. currentToken ( ) ;
text. skipToken ( name) ;
if ( ! name. equals ( "PRINT" ) && ! name. equals ( "BREAK" ) && ! name. equals ( "SPACE" ) ) {
System. err. println ( "非法命令!" ) ;
}
if ( name. equals ( "PRINT" ) ) {
textStr = text. currentToken ( ) ;
text. nextToken ( ) ;
}
}
@Override
public void execute ( ) {
if ( name. equals ( "PRINT" ) ) {
System. out. print ( textStr) ; }
else if ( name. equals ( "SPACE" ) ) {
System. out. print ( " " ) ; }
else if ( name. equals ( "BREAK" ) ) {
System. out. println ( ) ; }
}
}
public class Main {
public static void main(String[] args){
String text = "LOOP 2 PRINT 杨过 SPACE SPACE PRINT 小龙女 BREAK END PRINT 郭靖 SPACE SPACE PRINT 黄蓉";
Context context = new Context(text);
Expression expression = new ExpressionNode();
expression.interpreter(context);
expression.execute();
}
}
解释器模式的优缺点 优点: 可扩展性比较好;增加了新的解释表达式的方式;易于实现简单文法。 缺点: 该模式比较难以理解,可利用的场景少,有可能会造成类爆炸,由于该模式采用的事递归,不利于调试。