行为型设计模式-解释器模式
定义
给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
文法:即语法规则。在解释器模式中每一个语法都将对应一个解释器对象,用来处理相应的语法规则。它对于扩展、改变文法以及增加新的文法规则都很方便。
解释器模式描述了如何为简单的语言定义一个文法,如何在该语言中表示一个句子,以及如何解释这些句子。
在解释器模式中可以通过一种称之为抽象语法树(Abstract Syntax Tree, AST)的图形方式来直观地表示语言的构成,每一棵抽象语法树对应一个语言实例
角色
- AbstractExpression: 抽象表达式,声明一个抽象的解释操作父类,定义一个抽象的解释方法,具体的实现由子类解释器完成/
- TerminalExpression: 终结符表达式,实现文法中与终结符有关的解释操作,文法中每一个终结符都有一个具体的终结表达式与之对应
- NonterminalExpression: 非终结符表达式,实现文法中与非终结符有关的解释操作
- Context: 上下文环境类,包含解释器之外的全局信息
- Client: 客户端,解析表达式,构建抽象语法树,执行具体的解释操作等.
解释器UML 图
解释器UML 图场景模拟
四则运算
四则运算简单代码
只实现了加法和减法
#import <Foundation/Foundation.h>
@protocol ArithmeticExpression <NSObject>
-(int)interptet;
@end
#import <Foundation/Foundation.h>
#import "ArithmeticExpression.h"
@interface NumExpression : NSObject<ArithmeticExpression>
- (instancetype)initWithNum:(int)num;
@end
#import "NumExpression.h"
@interface NumExpression()
@property (nonatomic,assign) int num;
@end
@implementation NumExpression
- (instancetype)initWithNum:(int)num
{
self = [super init];
if (self) {
self.num = num;
}
return self;
}
-(int)interptet{
return self.num;
}
@end
#import <Foundation/Foundation.h>
#import "ArithmeticExpression.h"
@interface OperatorExpression : NSObject<ArithmeticExpression>
{
@protected
id<ArithmeticExpression> _mArithmeticExpression1;
id<ArithmeticExpression> _mArithmeticExpression2;
}
-(void)OperatorExpression:(id<ArithmeticExpression>)mArithmeticExpression1 :(id<ArithmeticExpression>)mArithmeticExpression2;
@end
import "OperatorExpression.h"
@interface OperatorExpression()
@end
@implementation OperatorExpression
-(void)OperatorExpression:(id<ArithmeticExpression>)mArithmeticExpression1 :(id<ArithmeticExpression>)mArithmeticExpression2{
_mArithmeticExpression1 = mArithmeticExpression1;
_mArithmeticExpression2 = mArithmeticExpression2;
}
#import <Foundation/Foundation.h>
#import "ArithmeticExpression.h"
#import "NumExpression.h"
#import "AdditionExpression.h"
#import "ReduceExpression.h"
@interface Calculator : NSObject
-(void)calculator:(NSString *)expression;
-(int)calculator;
@end
#import "Calculator.h"
@interface Calculator()
@property (nonatomic,strong) NSMutableArray *mArithmeticExpressionStack;
@end
@implementation Calculator
- (instancetype)init
{
self = [super init];
if (self) {
self.mArithmeticExpressionStack = [NSMutableArray new];
}
return self;
}
-(void)calculator:(NSString *)expression{
id<ArithmeticExpression> one;
id <ArithmeticExpression> two;
while (1) {
if ([expression hasPrefix:@"+"]) {
one = [self.mArithmeticExpressionStack lastObject];
[self.mArithmeticExpressionStack removeLastObject];
expression = [expression substringFromIndex:1];
int b =[expression intValue];
expression = [self getExpression:expression];
two = [[NumExpression alloc]initWithNum:b];
AdditionExpression * add= [AdditionExpression new];
[ add OperatorExpression:one :two];
[self.mArithmeticExpressionStack addObject:add];
if (expression.length==0) {
break;
}
}else if ([expression hasPrefix:@"-"]){
one = [self.mArithmeticExpressionStack lastObject];
[self.mArithmeticExpressionStack removeLastObject];
expression = [expression substringFromIndex:1];
int b =[expression intValue];
expression = [self getExpression:expression];
two = [[NumExpression alloc]initWithNum:b];
ReduceExpression * add= [ReduceExpression new];
[ add OperatorExpression:one :two];
[self.mArithmeticExpressionStack addObject:add];
if (expression.length==0) {
break;
}
}
else{
int a=[expression intValue];
NumExpression * num = [[NumExpression alloc]initWithNum:a];
[self.mArithmeticExpressionStack addObject:num];
expression = [self getExpression:expression];
if (expression.length==0) {
break;
}
}
}
}
-(NSString *)getExpression:(NSString *)expression{
int a=[expression intValue];
NSString * str =[NSString stringWithFormat:@"%d",a];
return [expression substringFromIndex:str.length];
}
-(int)calculator{
id<ArithmeticExpression> object= [self.mArithmeticExpressionStack lastObject];
[self.mArithmeticExpressionStack removeLastObject];
return [object interptet];
}
#import "OperatorExpression.h"
@interface ReduceExpression : OperatorExpression
@end
#import "ReduceExpression.h"
@implementation ReduceExpression
-(int)interptet{
return [_mArithmeticExpression1 interptet]-[_mArithmeticExpression2 interptet];
}
@end
测试代码
Calculator * calculator = [Calculator new];
[calculator calculator:@"125+175+100-100"];
int result= [calculator calculator];
NSLog(@"result %d",result);
测试结果
2018-04-10 16:28:46.682503+0800 行为型设计模式-解释器模式[56577:8311175] result 300
这里需要解释下,要看肯定看的晕
1.ReduceExpression 和AdditionExpression 代表 NonterminalExpression
2.NumExpression代表TerminalExpression
3.Calculator 代表Client
4.ArithmeticExpression 协议代表AbstractExpression
5.vc 就代表context
这里的Calculator 相当于翻译机,将context给的内容翻译成ArithmeticExpression 协议类型的对象保存起来。
例如 "+" 号 ,我们知道是两目操作符,需要两个NumExpression 的数字。在Calculator 中如果遇到+ 号操作符,我们就需要获取两个
NumExpression 类型的数据。获取非常的繁琐。
乘法当时想实现乘法和除法的算法,想想还是算了。乘法和除法运算符需要考虑优先级问题了。就没有实现。实现思路如下图
demo中还实现了下面的场景
//行为型模式:解释器模式
//场景:开发一套机器人控制程序
/*说明:
机器人控制程序中包含一些简单的英文控制指令,每一个指令对应一个表达式(expression),
该表达式可以是简单表达式也可以是复合表达式,每一个简单表达式由移动方向(direction),
移动方式(action)和移动距离(distance)三部分组成,其中移动方向包括上(up)、下(down)、
左(left)、右(right);移动方式包括移动(move)和快速移动(run);移动距离为一个正整数。
两个表达式之间可以通过与(and)连接,形成复合(composite)表达式。
用户通过对图形化的设置界面进行操作可以创建一个机器人控制指令,机器人在收到指令
后将按照指令的设置进行移动,例如输入控制指令:up move 5,则“向上移动5个单位”;输入控
制指令:down run 10 and left move 20,则“向下快速移动10个单位再向左移动20个单位”。
*/
/*文法规则
expression ::= direction action distance | composite //表达式
composite ::= expression 'and' expression //复合表达式
direction ::= 'up' | 'down' | 'left' | 'right' //移动方向
action ::= 'move' | 'run' //移动方式
distance ::= an integer //移动距离
上述语言一共定义了五条文法规则,对应五个语言单位,这些语言单位可以分为两类,
终结符(也称为终结符表达式):例如direction、action和distance,它们是语言的最小组成单位,不能再进行拆分;
非终结符(也称为非终结符表达式),例如expression和composite,它们都是一个完整的句子,包含一系列终结符或非终结符。
*/
优缺点
优点
1.易于实现文法:在解释器模式中,一条语法规则用一个解释器对象来解释执行。对于解释器的实现来讲,功能就变得比较简单,只需要考虑这一条语法规则的实现就可以了,其他的都不用管。
2.易于扩展新的语法。由于解释器采用类来描述语法规则,因此可以通过继承等机制创建相应的解释器对象,在创建抽象语法树的时候使用这个新的解释器对象就可以了。
缺点
1.执行效率较低。由于在解释器模式中使用了大量的循环和递归调用,因此在解释较为复杂的句子时其速度很慢,而且代码的调试过程也比较麻烦。
2.对于复杂文法难以维护。在解释器模式中,每一条规则至少需要定义一个类,因此如果一个语言包含太多文法规则,类的个数将会急剧增加,导致系统难以管理和维护,此时可以考虑使用语法分析程序等方式来取代解释器模式。
- 相关模式
(1)解释器和组合模式
这两种可以组合使用,一般非终结符解释器相当于组合模式中的组合对象,终结符解释器相当于叶子对象。
(2)解释器模式和迭代器模式
由于解释器模式通常使用组合模式来实现,因此在遍历整个对象结构时,可以使用迭代器模式。
(3)解释器模式和享元模式
在使用解释器模式的时候,可能会造成多个细粒度对象,如各式各样的终结符解释器,而这些终结符解释器对不同的表达式来说是一样的,是可以共用的,因此可以引入享元模式来共享这些对象。
(4)解释器模式和访问者模式
在解释器模式中,语法规则和解释器对象是有对应关系的。语法规则的变动意味着功能的变化。自然会导致使用不同的解释器对象;而且一个语法规由可以被不同的解释器解释执行。因此在构建抽象语法树的时候,如果每个节点所对应的解释器对象是固定的,这意味着该节点对应的功能是固定的,那么就不得不根据需要来构建不同的抽象语法树。
为了让构建的抽象语法树较为通用,那就要求解释器的功能不要那么固定,要能很方便地改变解释器的功能,这个时候就变成了如何能够很方便地更改树形结构中节点对象的功能了,访问者模式可以很好的实现这个功能。
[借鉴博客](https://www.cnblogs.com/5iedu/p/5595153.html)
源代码地址
下一篇博客
行为型设计模式-迭代器模式