定義
給定一個(gè)語(yǔ)言,定義它的文法的一種表示焚虱,并定義一個(gè)解釋器,這個(gè)解釋器使用該表示來(lái)解釋語(yǔ)言中的句子懂版。
文法:即語(yǔ)法規(guī)則鹃栽。在解釋器模式中每一個(gè)語(yǔ)法都將對(duì)應(yīng)一個(gè)解釋器對(duì)象,用來(lái)處理相應(yīng)的語(yǔ)法規(guī)則躯畴。它對(duì)于擴(kuò)展民鼓、改變文法以及增加新的文法規(guī)則都很方便。
解釋器模式描述了如何為簡(jiǎn)單的語(yǔ)言定義一個(gè)文法蓬抄,如何在該語(yǔ)言中表示一個(gè)句子丰嘉,以及如何解釋這些句子。
在解釋器模式中可以通過(guò)一種稱(chēng)之為抽象語(yǔ)法樹(shù)(Abstract Syntax Tree, AST)的圖形方式來(lái)直觀地表示語(yǔ)言的構(gòu)成嚷缭,每一棵抽象語(yǔ)法樹(shù)對(duì)應(yīng)一個(gè)語(yǔ)言實(shí)例
角色
- AbstractExpression: 抽象表達(dá)式,聲明一個(gè)抽象的解釋操作父類(lèi),定義一個(gè)抽象的解釋方法,具體的實(shí)現(xiàn)由子類(lèi)解釋器完成/
- TerminalExpression: 終結(jié)符表達(dá)式,實(shí)現(xiàn)文法中與終結(jié)符有關(guān)的解釋操作,文法中每一個(gè)終結(jié)符都有一個(gè)具體的終結(jié)表達(dá)式與之對(duì)應(yīng)
- NonterminalExpression: 非終結(jié)符表達(dá)式,實(shí)現(xiàn)文法中與非終結(jié)符有關(guān)的解釋操作
- Context: 上下文環(huán)境類(lèi),包含解釋器之外的全局信息
- Client: 客戶(hù)端,解析表達(dá)式,構(gòu)建抽象語(yǔ)法樹(shù),執(zhí)行具體的解釋操作等.
解釋器UML 圖
場(chǎng)景模擬
四則運(yùn)算
四則運(yùn)算簡(jiǎn)單代碼
只實(shí)現(xiàn)了加法和減法
#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
測(cè)試代碼
Calculator * calculator = [Calculator new];
[calculator calculator:@"125+175+100-100"];
int result= [calculator calculator];
NSLog(@"result %d",result);
測(cè)試結(jié)果
2018-04-10 16:28:46.682503+0800 行為型設(shè)計(jì)模式-解釋器模式[56577:8311175] result 300
這里需要解釋下饮亏,要看肯定看的暈
1.ReduceExpression 和AdditionExpression 代表 NonterminalExpression
2.NumExpression代表TerminalExpression
3.Calculator 代表Client
4.ArithmeticExpression 協(xié)議代表AbstractExpression
5.vc 就代表context
這里的Calculator 相當(dāng)于翻譯機(jī),將context給的內(nèi)容翻譯成ArithmeticExpression 協(xié)議類(lèi)型的對(duì)象保存起來(lái)阅爽。
例如 "+" 號(hào) ,我們知道是兩目操作符路幸,需要兩個(gè)NumExpression 的數(shù)字。在Calculator 中如果遇到+ 號(hào)操作符付翁,我們就需要獲取兩個(gè)
NumExpression 類(lèi)型的數(shù)據(jù)简肴。獲取非常的繁瑣。
當(dāng)時(shí)想實(shí)現(xiàn)乘法和除法的算法百侧,想想還是算了砰识。乘法和除法運(yùn)算符需要考慮優(yōu)先級(jí)問(wèn)題了。就沒(méi)有實(shí)現(xiàn)佣渴。實(shí)現(xiàn)思路如下圖
demo中還實(shí)現(xiàn)了下面的場(chǎng)景
//行為型模式:解釋器模式
//場(chǎng)景:開(kāi)發(fā)一套機(jī)器人控制程序
/*說(shuō)明:
機(jī)器人控制程序中包含一些簡(jiǎn)單的英文控制指令辫狼,每一個(gè)指令對(duì)應(yīng)一個(gè)表達(dá)式(expression),
該表達(dá)式可以是簡(jiǎn)單表達(dá)式也可以是復(fù)合表達(dá)式辛润,每一個(gè)簡(jiǎn)單表達(dá)式由移動(dòng)方向(direction)予借,
移動(dòng)方式(action)和移動(dòng)距離(distance)三部分組成,其中移動(dòng)方向包括上(up)、下(down)灵迫、
左(left)秦叛、右(right);移動(dòng)方式包括移動(dòng)(move)和快速移動(dòng)(run)瀑粥;移動(dòng)距離為一個(gè)正整數(shù)挣跋。
兩個(gè)表達(dá)式之間可以通過(guò)與(and)連接,形成復(fù)合(composite)表達(dá)式狞换。
用戶(hù)通過(guò)對(duì)圖形化的設(shè)置界面進(jìn)行操作可以創(chuàng)建一個(gè)機(jī)器人控制指令避咆,機(jī)器人在收到指令
后將按照指令的設(shè)置進(jìn)行移動(dòng),例如輸入控制指令:up move 5修噪,則“向上移動(dòng)5個(gè)單位”查库;輸入控
制指令:down run 10 and left move 20,則“向下快速移動(dòng)10個(gè)單位再向左移動(dòng)20個(gè)單位”黄琼。
*/
/*文法規(guī)則
expression ::= direction action distance | composite //表達(dá)式
composite ::= expression 'and' expression //復(fù)合表達(dá)式
direction ::= 'up' | 'down' | 'left' | 'right' //移動(dòng)方向
action ::= 'move' | 'run' //移動(dòng)方式
distance ::= an integer //移動(dòng)距離
上述語(yǔ)言一共定義了五條文法規(guī)則樊销,對(duì)應(yīng)五個(gè)語(yǔ)言單位,這些語(yǔ)言單位可以分為兩類(lèi)脏款,
終結(jié)符(也稱(chēng)為終結(jié)符表達(dá)式):例如direction围苫、action和distance,它們是語(yǔ)言的最小組成單位撤师,不能再進(jìn)行拆分剂府;
非終結(jié)符(也稱(chēng)為非終結(jié)符表達(dá)式),例如expression和composite剃盾,它們都是一個(gè)完整的句子腺占,包含一系列終結(jié)符或非終結(jié)符。
*/
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
1.易于實(shí)現(xiàn)文法:在解釋器模式中痒谴,一條語(yǔ)法規(guī)則用一個(gè)解釋器對(duì)象來(lái)解釋執(zhí)行湾笛。對(duì)于解釋器的實(shí)現(xiàn)來(lái)講,功能就變得比較簡(jiǎn)單闰歪,只需要考慮這一條語(yǔ)法規(guī)則的實(shí)現(xiàn)就可以了嚎研,其他的都不用管。
2.易于擴(kuò)展新的語(yǔ)法库倘。由于解釋器采用類(lèi)來(lái)描述語(yǔ)法規(guī)則临扮,因此可以通過(guò)繼承等機(jī)制創(chuàng)建相應(yīng)的解釋器對(duì)象,在創(chuàng)建抽象語(yǔ)法樹(shù)的時(shí)候使用這個(gè)新的解釋器對(duì)象就可以了教翩。
缺點(diǎn)
1.執(zhí)行效率較低杆勇。由于在解釋器模式中使用了大量的循環(huán)和遞歸調(diào)用,因此在解釋較為復(fù)雜的句子時(shí)其速度很慢饱亿,而且代碼的調(diào)試過(guò)程也比較麻煩蚜退。
2.對(duì)于復(fù)雜文法難以維護(hù)闰靴。在解釋器模式中,每一條規(guī)則至少需要定義一個(gè)類(lèi)钻注,因此如果一個(gè)語(yǔ)言包含太多文法規(guī)則蚂且,類(lèi)的個(gè)數(shù)將會(huì)急劇增加,導(dǎo)致系統(tǒng)難以管理和維護(hù)幅恋,此時(shí)可以考慮使用語(yǔ)法分析程序等方式來(lái)取代解釋器模式杏死。
- 相關(guān)模式
(1)解釋器和組合模式
這兩種可以組合使用,一般非終結(jié)符解釋器相當(dāng)于組合模式中的組合對(duì)象捆交,終結(jié)符解釋器相當(dāng)于葉子對(duì)象淑翼。
(2)解釋器模式和迭代器模式
由于解釋器模式通常使用組合模式來(lái)實(shí)現(xiàn),因此在遍歷整個(gè)對(duì)象結(jié)構(gòu)時(shí)品追,可以使用迭代器模式玄括。
(3)解釋器模式和享元模式
在使用解釋器模式的時(shí)候,可能會(huì)造成多個(gè)細(xì)粒度對(duì)象肉瓦,如各式各樣的終結(jié)符解釋器遭京,而這些終結(jié)符解釋器對(duì)不同的表達(dá)式來(lái)說(shuō)是一樣的,是可以共用的风宁,因此可以引入享元模式來(lái)共享這些對(duì)象。
(4)解釋器模式和訪問(wèn)者模式
在解釋器模式中蛹疯,語(yǔ)法規(guī)則和解釋器對(duì)象是有對(duì)應(yīng)關(guān)系的戒财。語(yǔ)法規(guī)則的變動(dòng)意味著功能的變化。自然會(huì)導(dǎo)致使用不同的解釋器對(duì)象捺弦;而且一個(gè)語(yǔ)法規(guī)由可以被不同的解釋器解釋執(zhí)行饮寞。因此在構(gòu)建抽象語(yǔ)法樹(shù)的時(shí)候,如果每個(gè)節(jié)點(diǎn)所對(duì)應(yīng)的解釋器對(duì)象是固定的列吼,這意味著該節(jié)點(diǎn)對(duì)應(yīng)的功能是固定的幽崩,那么就不得不根據(jù)需要來(lái)構(gòu)建不同的抽象語(yǔ)法樹(shù)。
為了讓構(gòu)建的抽象語(yǔ)法樹(shù)較為通用寞钥,那就要求解釋器的功能不要那么固定慌申,要能很方便地改變解釋器的功能,這個(gè)時(shí)候就變成了如何能夠很方便地更改樹(shù)形結(jié)構(gòu)中節(jié)點(diǎn)對(duì)象的功能了理郑,訪問(wèn)者模式可以很好的實(shí)現(xiàn)這個(gè)功能蹄溉。
[借鑒博客](https://www.cnblogs.com/5iedu/p/5595153.html)
源代碼地址
下一篇博客
行為型設(shè)計(jì)模式-迭代器模式