iOS 設(shè)計(jì)模式之十七(迭代器模式)

一免猾、概念

1、迭代器模式的動(dòng)機(jī)

? 平時(shí)我們經(jīng)常使用for循環(huán)直接對數(shù)據(jù)進(jìn)行遍歷掘猿,但是如何對外提供遍歷的接口呢扶认,同時(shí)也不暴露自己的私有屬性。這個(gè)時(shí)候迭代器模式就很有用處了闷哆,本文將介紹迭代器模式的設(shè)計(jì)腰奋。

2单起、迭代器模式的定義

? 迭代器模式(Iterator Pattern):提供一種方法來訪問聚合對象抱怔,而不用暴露這個(gè)對象的內(nèi)部表示,其別名為游標(biāo) (Cursor)嘀倒。迭代器模式是一種對象行為型模式屈留。

3、迭代器模式的4個(gè)角色

1)Iterator(抽象迭代器):它定義了訪問和遍歷元素的接口测蘑,聲明了用于遍歷數(shù)據(jù)元素的方法灌危,例如:用于獲取第一個(gè)元素的first()方法,用于訪問下一個(gè)元素的next()方法碳胳,用于判斷是否還有下一個(gè)元素的hasNext()方法勇蝙,用于獲取當(dāng)前元素的currentItem()方法等,在具體迭代器中將實(shí)現(xiàn)這些方法挨约。

2)ConcreteIterator(具體迭代器):它實(shí)現(xiàn)了抽象迭代器接口味混,完成對聚合對象的遍歷,同時(shí)在具體迭代器中通過游標(biāo)來記錄在聚合對象中所處的當(dāng)前位置诫惭,在具體實(shí)現(xiàn)時(shí)翁锡,游標(biāo)通常是一個(gè)表示位置的非負(fù)整數(shù)。

3)Aggregate(抽象聚合類):它用于存儲和管理元素對象夕土,聲明一個(gè)createIterator()方法用于創(chuàng)建一個(gè)迭代器對象馆衔,充當(dāng)抽象迭代器工廠角色。

4)ConcreteAggregate(具體聚合類):它實(shí)現(xiàn)了在抽象聚合類中聲明的createIterator()方法怨绣,該方法返回一個(gè)與該具體聚合類對應(yīng)的具體迭代器ConcreteIterator實(shí)例角溃。

? 在迭代器模式結(jié)構(gòu)中包含聚合和迭代器兩個(gè)層次結(jié)構(gòu),考慮到系統(tǒng)的靈活性和可擴(kuò)展性篮撑,在迭代器模式中應(yīng)用了工廠方法模式减细。

4、結(jié)構(gòu)圖
迭代器模式

二咽扇、示例

1)先創(chuàng)建一個(gè)AbstractIterator協(xié)議邪财,里面有一些迭代器的方法陕壹,表示抽象迭代器;

2)然后創(chuàng)建ProductIterator類树埠,有一個(gè)初始化方法糠馆,遵循AbstractIterator協(xié)議,表示具體迭代器怎憋;

3)然后創(chuàng)建AbstractObjectList類又碌,聲明了創(chuàng)建迭代器方法createIterator(),表示抽象聚合類绊袋;

4)最后創(chuàng)建ProductList類毕匀,繼承自AbstractObjectList,并實(shí)現(xiàn)createIterator()方法癌别,表示具體聚合類皂岔。

具體代碼如下:

AbstractIterator協(xié)議:

@protocol AbstractIterator <NSObject>
- (void)next;
- (BOOL)isLast;
- (id)getCurrentItem;
@end

typedef id<AbstractIterator> AbstractIterator;

ProductIterator類:

// 商品迭代器:具體迭代器
@interface ProductIterator : NSObject<AbstractIterator>
- (instancetype)initWithProductList:(ProductList *)list;
@end

@interface ProductIterator ()
@property(nonatomic, strong) NSArray *objects;
@property(nonatomic, assign) NSInteger index;
@end
@implementation ProductIterator
- (instancetype)initWithProductList:(ProductList *)list {
    self = [super init];
    if (self) {
        _objects = [list getObjects];
        _index = 0;
    }
    return self;
}

- (void)next {
    if (self.index < self.objects.count) {
        self.index ++;
    }
}

- (BOOL)isLast {
    return (self.index == self.objects.count);
}

- (id)getCurrentItem {
    return self.objects[self.index];
}
@end

AbstractObjectList類:

// 抽象聚合類
@interface AbstractObjectList : NSObject
- (void)addObject:(id)object;
- (void)removeObject:(id)object;
- (NSArray *)getObjects;
// 聲明創(chuàng)建迭代器對象的抽象工廠方法
- (AbstractIterator)createIterator;
@end

@interface AbstractObjectList ()
@property(nonatomic, strong) NSMutableArray *objects;
@end
@implementation AbstractObjectList
- (instancetype)init
{
    self = [super init];
    if (self) {
        _objects = [NSMutableArray array];
    }
    return self;
}

- (void)addObject:(id)object {
    [self.objects addObject:object];
}

- (void)removeObject:(id)object {
    [self.objects removeObject:object];
}

- (NSArray *)getObjects {
    return self.objects;
}

- (AbstractIterator)createIterator {
    return nil;
}
@end

ProductList類:

// 商品數(shù)據(jù)類:具體聚合類
@interface ProductList : AbstractObjectList
@end

@implementation ProductList
- (AbstractIterator)createIterator {
    return [[ProductIterator alloc] initWithProductList:self];
}
@end

運(yùn)行代碼:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    ProductList *products = [ProductList new];
    [products addObject:@"蘋果"];
    [products addObject:@"香蕉"];
    [products addObject:@"橘子"];

    AbstractIterator iterator = [products createIterator];
    while (![iterator isLast]) {
        NSLog(@"%@", [iterator getCurrentItem]);
        [iterator next];
    }
}

打印結(jié)果:

蘋果
香蕉
橘子

三、總結(jié)

? 迭代器模式是一種使用頻率非常高的設(shè)計(jì)模式展姐,通過引入迭代器可以將數(shù)據(jù)的遍歷功能從聚合對象中分離出來躁垛,聚合對象只負(fù)責(zé)存儲數(shù)據(jù),而遍歷數(shù)據(jù)由迭代器來完成圾笨。

1教馆、優(yōu)點(diǎn)

1、它支持以不同的方式遍歷一個(gè)聚合對象擂达,在同一個(gè)聚合對象上可以定義多種遍歷方式土铺。在迭代器模式中只需要用一個(gè)不同的迭代器來替換原有迭代器即可改變遍歷算法,我們也可以自己定義迭代器的子類以支持新的遍歷方式板鬓。

2悲敷、迭代器簡化了聚合類。由于引入了迭代器穗熬,在原有的聚合對象中不需要再自行提供數(shù)據(jù)遍歷等方法镀迂,這樣可以簡化聚合類的設(shè)計(jì)。

3唤蔗、 在迭代器模式中探遵,由于引入了抽象層,增加新的聚合類和迭代器類都很方便妓柜,無須修改原有代碼箱季,滿足“開閉原則”的要求。

2棍掐、缺點(diǎn)

1藏雏、由于迭代器模式將存儲數(shù)據(jù)和遍歷數(shù)據(jù)的職責(zé)分離,增加新的聚合類需要對應(yīng)增加新的迭代器類作煌,類的個(gè)數(shù)成對增加掘殴,這在一定程度上增加了系統(tǒng)的復(fù)雜性赚瘦。

2、抽象迭代器的設(shè)計(jì)難度較大奏寨,需要充分考慮到系統(tǒng)將來的擴(kuò)展起意,例如JDK內(nèi)置迭代器Iterator就無法實(shí)現(xiàn)逆向遍歷,如果需要實(shí)現(xiàn)逆向遍歷病瞳,只能通過其子類ListIterator等來實(shí)現(xiàn)揽咕,而ListIterator迭代器無法用于操作Set類型的聚合對象。在自定義迭代器時(shí)套菜,創(chuàng)建一個(gè)考慮全面的抽象迭代器并不是件很容易的事情亲善。

3、適用場景

1逗柴、訪問一個(gè)聚合對象的內(nèi)容而無須暴露它的內(nèi)部表示蛹头。將聚合對象的訪問與內(nèi)部數(shù)據(jù)的存儲分離,使得訪問聚合對象時(shí)無須了解其內(nèi)部實(shí)現(xiàn)細(xì)節(jié)嚎于。

2掘而、需要為一個(gè)聚合對象提供多種遍歷方式。

3于购、為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口,在該接口的實(shí)現(xiàn)類中為不同的聚合結(jié)構(gòu)提供不同的遍歷方式知染,而客戶端可以一致性地操作該接口肋僧。

4、iOS應(yīng)用舉例

? 這里介紹在Cocoa Touch框架中的四種迭代器模式控淡,當(dāng)然在iOS中枚舉器就是迭代器??嫌吠。

1)NSEnumerator:從iOS 2.0開始,可以使用NSEnumerator來枚舉NSArray掺炭、NSDictionary和NSSet對象中的元素辫诅。常見用法如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableArray *arr = [NSMutableArray array];
    [arr addObject:@"蘋果"];
    [arr addObject:@"香蕉"];
    [arr addObject:@"橘子"];
    
    NSEnumerator *iterator = [arr objectEnumerator];
    id fruit;
    while (fruit = [iterator nextObject]) {
        NSLog(@"%@", fruit);
    }
}

2)Block-Based Enumeration(塊的枚舉):從iOS 4.0開始,可以使用block的枚舉來遍歷集合對象中的元素涧狮。常見用法如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableArray *arr = [NSMutableArray array];
    [arr addObject:@"蘋果"];
    [arr addObject:@"香蕉"];
    [arr addObject:@"橘子"];
    
    [arr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSString *str = (NSString *)obj;
        NSLog(@"%@", str);
        if ([str isEqualToString:@"香蕉"]) {
            *stop = YES; // 提前停止枚舉
        }
    }];
}

3)快速枚舉:Objective-C 2.0提供一種枚舉炕矮,稱為快速枚舉,它是蘋果公司推薦的枚舉方法者冤》羰樱快速枚舉不需要使用其他枚舉器對象,而且比傳統(tǒng)的基于索引的for循環(huán)效率更高涉枫。常見用法如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableArray *arr = [NSMutableArray array];
    [arr addObject:@"蘋果"];
    [arr addObject:@"香蕉"];
    [arr addObject:@"橘子"];
    
    for (NSString *str in arr) {
        NSLog(@"%@", str);
    }
}

4)內(nèi)部枚舉:NSArray有個(gè)實(shí)例方法(void)makeObjectsPerformSelector:(SEL)aSelector邢滑,它允許客戶端向數(shù)組中的每個(gè)元素發(fā)送一個(gè)消息,讓每個(gè)元素執(zhí)行指定的選擇器aSelector愿汰。常見用法如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableArray *arr = [NSMutableArray array];
    [arr addObject:[UIView new]];
    [arr addObject:[UIView new]];
    [arr makeObjectsPerformSelector:@selector(removeFromSuperview)];
}

Demo地址:iOS-Design-Patterns

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末困后,一起剝皮案震驚了整個(gè)濱河市乐纸,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摇予,老刑警劉巖锯仪,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趾盐,居然都是意外死亡庶喜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門救鲤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來久窟,“玉大人,你說我怎么就攤上這事本缠〕饪福” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵丹锹,是天一觀的道長稀颁。 經(jīng)常有香客問我,道長楣黍,這世上最難降的妖魔是什么匾灶? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮租漂,結(jié)果婚禮上阶女,老公的妹妹穿的比我還像新娘。我一直安慰自己哩治,他們只是感情好秃踩,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著业筏,像睡著了一般憔杨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒜胖,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天消别,我揣著相機(jī)與錄音,去河邊找鬼翠勉。 笑死妖啥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的对碌。 我是一名探鬼主播荆虱,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怀读?” 一聲冷哼從身側(cè)響起诉位,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎菜枷,沒想到半個(gè)月后苍糠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡啤誊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年岳瞭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚊锹。...
    茶點(diǎn)故事閱讀 40,505評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瞳筏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出牡昆,到底是詐尸還是另有隱情姚炕,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布丢烘,位于F島的核電站柱宦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏播瞳。R本人自食惡果不足惜掸刊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狐史。 院中可真熱鬧痒给,春花似錦、人聲如沸骏全。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽姜贡。三九已至,卻和暖如春棺棵,著一層夾襖步出監(jiān)牢的瞬間楼咳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工烛恤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留母怜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓缚柏,卻偏偏與公主長得像苹熏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評論 2 359

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