一犬性、概念
1拱燃、解釋器模式的動(dòng)機(jī)
? 雖然目前計(jì)算機(jī)編程語(yǔ)言有好幾百種,但有時(shí)候我們還是希望能用一些簡(jiǎn)單的語(yǔ)言來(lái)實(shí)現(xiàn)一些特定的操作腾它,我們只要向計(jì)算機(jī)輸入一個(gè)句子或文件跑筝,它就能夠按照預(yù)先定義的文法規(guī)則來(lái)對(duì)句子或文件進(jìn)行解釋,從而實(shí)現(xiàn)相應(yīng)的功能瞒滴。例如提供一個(gè)簡(jiǎn)單的加法/減法解釋器曲梗,只要輸入一個(gè)加法/減法表達(dá)式,它就能夠計(jì)算出表達(dá)式結(jié)果妓忍,當(dāng)輸入字符串表達(dá)式為“1 + 2 + 3 – 4 + 1”時(shí)虏两,將輸出計(jì)算結(jié)果為3。
? 我們知道世剖,像Java和OC等語(yǔ)言無(wú)法直接解釋類似“1 + 2 + 3 – 4 + 1”這樣的字符串(如果直接作為數(shù)值表達(dá)式時(shí)可以解釋)定罢,我們必須自己定義一套文法規(guī)則來(lái)實(shí)現(xiàn)對(duì)這些語(yǔ)句的解釋,即設(shè)計(jì)一個(gè)自定義語(yǔ)言旁瘫,此時(shí)可以使用解釋器模式來(lái)實(shí)現(xiàn)自定義語(yǔ)言祖凫。
2、解釋器模式的定義
? 解釋器模式(Interpreter Pattern):定義一個(gè)語(yǔ)言的文法酬凳,并且建立一個(gè)解釋器來(lái)解釋該語(yǔ)言中的句子惠况,這里的“語(yǔ)言”是指使用規(guī)定格式和語(yǔ)法的代碼。解釋器模式是一種類行為型模式宁仔。
語(yǔ)言單位可以分為兩類:
1)終結(jié)符:也稱為終結(jié)符表達(dá)式稠屠,它們是語(yǔ)言的最小組成單位,不能再進(jìn)行拆分;
2)非終結(jié)符:也稱為非終結(jié)符表達(dá)式权埠,它們都是一個(gè)完整的句子榨了,包含一系列終結(jié)符或非終結(jié)符。
3攘蔽、解釋器模式的4個(gè)角色
1)AbstractExpression(抽象表達(dá)式):在抽象表達(dá)式中聲明了抽象的解釋操作阻逮,它是所有終結(jié)符表達(dá)式和非終結(jié)符表達(dá)式的公共父類。
2)TerminalExpression(終結(jié)符表達(dá)式):終結(jié)符表達(dá)式是抽象表達(dá)式的子類秩彤,它實(shí)現(xiàn)了與文法中的終結(jié)符相關(guān)聯(lián)的解釋操作叔扼,在句子中的每一個(gè)終結(jié)符都是該類的一個(gè)實(shí)例。通常在一個(gè)解釋器模式中只有少數(shù)幾個(gè)終結(jié)符表達(dá)式類漫雷,它們的實(shí)例可以通過(guò)非終結(jié)符表達(dá)式組成較為復(fù)雜的句子瓜富。
3)NonterminalExpression(非終結(jié)符表達(dá)式):非終結(jié)符表達(dá)式也是抽象表達(dá)式的子類,它實(shí)現(xiàn)了文法中非終結(jié)符的解釋操作降盹,由于在非終結(jié)符表達(dá)式中可以包含終結(jié)符表達(dá)式与柑,也可以繼續(xù)包含非終結(jié)符表達(dá)式,因此其解釋操作一般通過(guò)遞歸的方式來(lái)完成蓄坏。
4)Context(環(huán)境類):環(huán)境類又稱為上下文類价捧,它用于存儲(chǔ)解釋器之外的一些全局信息,通常它臨時(shí)存儲(chǔ)了需要解釋的語(yǔ)句涡戳。
4结蟋、結(jié)構(gòu)圖
二、示例
? 本示例是簡(jiǎn)單的將英語(yǔ)翻譯成中文渔彰,僅簡(jiǎn)單展示各個(gè)角色的使用嵌屎,實(shí)際操作更復(fù)雜。
1)先創(chuàng)建一個(gè)Context環(huán)境類恍涂,里面存放著需要解釋的中英文宝惰;
2)然后創(chuàng)建AbstractExpression抽象表達(dá)式,有一個(gè)interpretWithContext()方法再沧;
3)創(chuàng)建一個(gè)DirectionExpression類尼夺,英語(yǔ)方向解釋器,繼承自AbstractExpression類炒瘸,表示終結(jié)符表達(dá)式淤堵;
4)最后創(chuàng)建AndExpression類,繼承自AbstractExpression類什燕,表示非終結(jié)符表達(dá)式粘勒。
具體代碼如下:
Context類:
// 上下文
@interface Context : NSObject
- (NSString *)getObjectWithKey:(NSString *)key;
@end
@interface Context ()
@property(nonatomic, strong) NSMutableDictionary *dict;
@end
@implementation Context
- (instancetype)init
{
self = [super init];
if (self) {
_dict = [NSMutableDictionary dictionary];
[_dict setObject:@"向左" forKey:@"left"];
[_dict setObject:@"向右" forKey:@"right"];
[_dict setObject:@"向前" forKey:@"forward"];
[_dict setObject:@"向后" forKey:@"backward"];
}
return self;
}
- (NSString *)getObjectWithKey:(NSString *)key {
if ([self.dict.allKeys containsObject:key]) {
return [self.dict objectForKey:key];
}
return nil;
}
@end
AbstractExpression類:
@interface AbstractExpression : NSObject
- (NSString *)interpretWithContext:(Context *)context;
@end
@implementation AbstractExpression
- (NSString *)interpretWithContext:(Context *)context {
return nil;
}
@end
DirectionExpression類:
// 方向解釋:終結(jié)符表達(dá)式
@interface DirectionExpression : AbstractExpression
@property(nonatomic, copy) NSString *direction;
- (instancetype)initWithDirection:(NSString *)direction;
@end
@implementation DirectionExpression
- (instancetype)initWithDirection:(NSString *)direction {
self = [super init];
if (self) {
_direction = direction;
}
return self;
}
- (NSString *)interpretWithContext:(Context *)context {
NSString *result = [NSString stringWithFormat:@"[%@]", [context getObjectWithKey:self.direction]];
return result;
}
@end
AndExpression類:
// And解釋:非終結(jié)符表達(dá)式
@interface AndExpression : AbstractExpression
@property(nonatomic, strong) AbstractExpression *leftExpression;
@property(nonatomic, strong) AbstractExpression *rightExpression;
- (instancetype)initWithLeft:(AbstractExpression *)left right:(AbstractExpression *)right;
@end
@implementation AndExpression
- (instancetype)initWithLeft:(AbstractExpression *)left right:(AbstractExpression *)right {
self = [super init];
if (self) {
_leftExpression = left;
_rightExpression = right;
}
return self;
}
- (NSString *)interpretWithContext:(Context *)context {
NSString *leftStr = [self.leftExpression interpretWithContext:context];
NSString *rightStr = [self.rightExpression interpretWithContext:context];
NSString *result = [NSString stringWithFormat:@"%@ 再 %@", leftStr, rightStr];
return result;
}
@end
運(yùn)行代碼:
- (void)viewDidLoad {
[super viewDidLoad];
// 實(shí)現(xiàn)英語(yǔ)翻譯成中文的效果
Context *context = [Context new];
DirectionExpression *leftDir = [[DirectionExpression alloc] initWithDirection:@"left"];
DirectionExpression *rightDir = [[DirectionExpression alloc] initWithDirection:@"right"];
NSLog(@"終結(jié)符表達(dá)式:%@", [leftDir interpretWithContext:context]);
AndExpression *andExp = [[AndExpression alloc] initWithLeft:leftDir right:rightDir];
NSLog(@"非終結(jié)符表達(dá)式:%@", [andExp interpretWithContext:context]);
}
打印結(jié)果:
終結(jié)符表達(dá)式:[向左]
非終結(jié)符表達(dá)式:[向左] 再 [向右]
三、總結(jié)
? 解釋器模式為自定義語(yǔ)言的設(shè)計(jì)和實(shí)現(xiàn)提供了一種解決方案屎即,它用于定義一組文法規(guī)則并通過(guò)這組文法規(guī)則來(lái)解釋語(yǔ)言中的句子。雖然解釋器模式的使用頻率不是特別高,但是它在正則表達(dá)式技俐、XML文檔解釋等領(lǐng)域還是得到了廣泛使用乘陪。
1、優(yōu)點(diǎn)
1雕擂、易于改變和擴(kuò)展文法啡邑。由于在解釋器模式中使用類來(lái)表示語(yǔ)言的文法規(guī)則,因此可以通過(guò)繼承等機(jī)制來(lái)改變或擴(kuò)展文法井赌。
2谤逼、每一條文法規(guī)則都可以表示為一個(gè)類,因此可以方便地實(shí)現(xiàn)一個(gè)簡(jiǎn)單的語(yǔ)言仇穗。
3流部、增加新的解釋表達(dá)式較為方便。如果用戶需要增加新的解釋表達(dá)式只需要對(duì)應(yīng)增加一個(gè)新的終結(jié)符表達(dá)式或非終結(jié)符表達(dá)式類纹坐,原有表達(dá)式類代碼無(wú)須修改枝冀,符合“開(kāi)閉原則”。
2耘子、缺點(diǎn)
1果漾、對(duì)于復(fù)雜文法難以維護(hù)。在解釋器模式中谷誓,每一條規(guī)則至少需要定義一個(gè)類绒障,因此如果一個(gè)語(yǔ)言包含太多文法規(guī)則,類的個(gè)數(shù)將會(huì)急劇增加捍歪,導(dǎo)致系統(tǒng)難以管理和維護(hù)端盆,此時(shí)可以考慮使用語(yǔ)法分析程序等方式來(lái)取代解釋器模式。
2费封、執(zhí)行效率較低焕妙。由于在解釋器模式中使用了大量的循環(huán)和遞歸調(diào)用,因此在解釋較為復(fù)雜的句子時(shí)其速度很慢弓摘,而且代碼的調(diào)試過(guò)程也比較麻煩焚鹊。
3、適用場(chǎng)景
1韧献、可以將一個(gè)需要解釋執(zhí)行的語(yǔ)言中的句子表示為一個(gè)抽象語(yǔ)法樹(shù)末患,執(zhí)行效率不是關(guān)鍵問(wèn)題。
2锤窑、一些重復(fù)出現(xiàn)的問(wèn)題可以用一種簡(jiǎn)單的語(yǔ)言來(lái)進(jìn)行表達(dá)璧针。
3、一個(gè)語(yǔ)言的文法較為簡(jiǎn)單渊啰。
4探橱、iOS應(yīng)用舉例
? 比如判斷郵件地址申屹、電話號(hào)碼、證件號(hào)碼是否是正確的正則表達(dá)式隧膏,就是應(yīng)用了解釋器模式哗讥。
Demo地址:iOS-Design-Patterns