一免猾、概念
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