iOS 設(shè)計(jì)模式之十六(解釋器模式)

一犬性、概念

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市胞枕,隨后出現(xiàn)的幾起案子杆煞,更是在濱河造成了極大的恐慌,老刑警劉巖腐泻,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件决乎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡派桩,警方通過(guò)查閱死者的電腦和手機(jī)构诚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)窄坦,“玉大人唤反,你說(shuō)我怎么就攤上這事⊙冀颍” “怎么了彤侍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)逆趋。 經(jīng)常有香客問(wèn)我盏阶,道長(zhǎng),這世上最難降的妖魔是什么闻书? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任名斟,我火速辦了婚禮,結(jié)果婚禮上魄眉,老公的妹妹穿的比我還像新娘砰盐。我一直安慰自己,他們只是感情好坑律,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布岩梳。 她就那樣靜靜地躺著,像睡著了一般晃择。 火紅的嫁衣襯著肌膚如雪冀值。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天宫屠,我揣著相機(jī)與錄音列疗,去河邊找鬼。 笑死浪蹂,一個(gè)胖子當(dāng)著我的面吹牛抵栈,可吹牛的內(nèi)容都是我干的告材。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼竭讳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼创葡!你這毒婦竟也來(lái)了浙踢?” 一聲冷哼從身側(cè)響起绢慢,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洛波,沒(méi)想到半個(gè)月后胰舆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蹬挤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年缚窿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焰扳。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡倦零,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吨悍,到底是詐尸還是另有隱情扫茅,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布育瓜,位于F島的核電站葫隙,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏躏仇。R本人自食惡果不足惜恋脚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望焰手。 院中可真熱鬧糟描,春花似錦、人聲如沸书妻。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)驻子。三九已至灿意,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間崇呵,已是汗流浹背缤剧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留域慷,地道東北人荒辕。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓汗销,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抵窒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子弛针,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容