解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式,它属于行为型模式.这种模式实现了一个表达式接口,该接口解释一个特定的上下文.
这种模式被用在 SQL 解析、符号处理引擎等。
模式结构和说明
解释器模式主要包括以下几个角色:
AbstractExpression:抽象表达式.声明一个抽象的解释操作,该接口为抽象语法树种所有的节点共享
TerminalExpression:终结符表达式.实现与文法中的终结符相关的解释操作.实现抽象表达式中所要求的方法.文法中每一个终结符都有一个具体的终结表达式与之相对应
NonterminalExpression:非终结符表达式。为文法中的非终结符相关的解释操作
Context:环境类.包含解释器之外的一些全局信息
抽象语法树描述了图和构成一个复杂的句子,通过对抽象语法树的分析,可以识别出语言中的终结符和非终结符.在解释器模式中由于每一种终结符表达式,非终结符表达式都会有一个具体的实例与之相对应,多以系统的扩展性比较好
示例代码
现在我们用解释器模式来实现一个基本的加、减、乘、除和求模运算。例如用户输入表达式“3 * 4 / 2 % 4”,输出结果为2
- 定义抽象表达式node
@implementation Node
- (int)interpret
{
return 0;
}
@end
从上面的表达式可以,终结符有两种,一种是数字,另一个中是变量
2. 定义终结符表达式
@implementation ValueNode
+ (instancetype)valueNodeWithValue:(int)value
{
ValueNode *node = [[ValueNode alloc] init];
node.value = value;
return node;
}
- (int)interpret
{
return self.value;
}
@end
@implementation SymbolNode
+ (instancetype)symbolNodeWithLeft:(Node *)left right:(Node *)right
{
SymbolNode *node = [[[self class] alloc] init];
node.leftN = left;
node.rightN = right;
return node;
}
@end
- 定义非终结表达式
@implementation MulNode
- (int)interpret
{
return self.leftN.interpret * self.rightN.interpret;
}
@end
@implementation ModNode
- (int)interpret
{
return self.leftN.interpret % self.rightN.interpret;
}
@end
@implementation DivNode
- (int)interpret
{
return self.leftN.interpret / self.rightN.interpret;
}
@end
- 客户端使用
Node *left = nil;
Node *right = nil;
NSMutableArray *nodeArr = [NSMutableArray array];
NSString *str = @"3 * 4 / 2";
NSArray *stateArr = [str componentsSeparatedByString:@" "];
for (int i = 0; i < stateArr.count; i++) {
if ([stateArr[i] isEqualToString:@"*"]) {
left = nodeArr.lastObject;
int value = [stateArr[++i] intValue];
right = [ValueNode valueNodeWithValue:value];
[nodeArr addObject:[MulNode symbolNodeWithLeft:left right:right]];
} else if ([stateArr[i] isEqualToString:@"/"]){
left = nodeArr.lastObject;
int value = [stateArr[++i] intValue];
right = [ValueNode valueNodeWithValue:value];
[nodeArr addObject:[DivNode symbolNodeWithLeft:left right:right]];
}else if ([stateArr[i] isEqualToString:@"%"]){
left = nodeArr.lastObject;
int value = [stateArr[++i] intValue];
right = [ValueNode valueNodeWithValue:value];
[nodeArr addObject:[ModNode symbolNodeWithLeft:left right:right]];
} else {
int value = [stateArr[i] intValue];
[nodeArr addObject:[ValueNode valueNodeWithValue:value]];
}
}
SymbolNode *node = nodeArr.lastObject;
NSLog(@"最终的值为%d",[node interpret]);
模式讲解
优点
灵活的扩展性,想扩展语法规则时只需新增新的解释器就可以了。如上面的例子中,想增加乘除法,只想增加相应的解释类,并增加相应的表达式解释操作即可
缺点
- 每一个文法都至少对应一个解释器,会产生大量的类,难于维护。
- 解释器模式由于大量使用循环和递归,需要考虑效率的问题,而且调试也不方便。
- 对于复杂的文法,构建其抽象语法树会显得异常繁琐。
- 所以不推荐在重要的模块中使用解释器模式,维护困难。
总结
解释器模式使用解释器对象来表示和处理相应的语法规则,一般一个解释器处理一条语法规则。理论上来说,只要能用解释器对象把符合语法的表达式表示出来,而且能够构成抽象的语法树,那都可以使用解释器模式来处理。