行為型設(shè)計(jì)模式-解釋器模式

定義

給定一個(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 圖

解釋器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)取代解釋器模式杏死。


  1. 相關(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ì)模式-迭代器模式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市您炉,隨后出現(xiàn)的幾起案子柒爵,更是在濱河造成了極大的恐慌,老刑警劉巖赚爵,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棉胀,死亡現(xiàn)場(chǎng)離奇詭異法瑟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)唁奢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)霎挟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人驮瞧,你說(shuō)我怎么就攤上這事氓扛。” “怎么了论笔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵采郎,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我狂魔,道長(zhǎng)蒜埋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任最楷,我火速辦了婚禮整份,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘籽孙。我一直安慰自己烈评,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布犯建。 她就那樣靜靜地躺著讲冠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪适瓦。 梳的紋絲不亂的頭發(fā)上竿开,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音玻熙,去河邊找鬼否彩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛嗦随,可吹牛的內(nèi)容都是我干的列荔。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼枚尼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肌毅!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起姑原,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤悬而,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后锭汛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體笨奠,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡袭蝗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了般婆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片到腥。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蔚袍,靈堂內(nèi)的尸體忽然破棺而出乡范,到底是詐尸還是另有隱情,我是刑警寧澤啤咽,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布晋辆,位于F島的核電站,受9級(jí)特大地震影響宇整,放射性物質(zhì)發(fā)生泄漏瓶佳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一鳞青、第九天 我趴在偏房一處隱蔽的房頂上張望霸饲。 院中可真熱鬧,春花似錦臂拓、人聲如沸厚脉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)傻工。三九已至,卻和暖如春童番,著一層夾襖步出監(jiān)牢的瞬間精钮,已是汗流浹背威鹿。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工剃斧, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忽你。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓幼东,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親科雳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子根蟹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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