在開發中,不同的場景適用不同的設計模式。對於開發建模方面,可以根據模型的抽象型別設計成簡單屬性模式和複雜組合模式。
因為組合模式中的屬性為多種型別物件,可操作性也比較靈活。
而針對這種複雜資料結構,有兩種設計模式可以使用:
1.組合模式
2.迭代器模式
組合模式篇
組合模式簡介:
1.組合模式就是一個樹形資料結構
2.對組合物件的查詢,訪問都是遞迴操作。
3.所有的節點都會實現同一套介面或者繼承自 同一個抽象父類。
4.每個物件都是其中的一個節點,無論葉子節點和元件節點都有相同的介面。只是葉子節點的介面返回為空,元件節點的介面實現介面。
5.組合模式讓我們把相同基型別的物件組合到樹狀結構中,其中父節點包含同型別的子節點
組合模式的物件圖如下:
aComposite:元件節點,下面包含子節點
aLeaf:葉子節點,下面沒有子節點。
組合模式的類圖如下:
aComposite:元件節點中包含的動作如下:
1.基本操作
2.對子節點的各種操作(增,刪,查)
aLeaf:葉子節點總包含的動作如下:
1.基本操作
因為葉子節點是最底層,最簡單的節點,所以它所包含的動作也是最簡單的,只有作用節點最基本的operation功能。
組合模式的作用:
1.將物件組合成樹形結構,以表示“整體-部分”的層次結構
2.組合模式使得客戶端對單個物件和組合物件的操作具有一致性。使客戶端對元件節點和葉子節點進行處理時,能夠對它們的區別無感知,好像它們都是同樣的簡單物件。
組合模式的實際使用例子:
線段軌跡這個抽象事物為例子,這個抽象例子中包含三種模型:
1.線段,它是一個組合模式模型,裡面可以包含子線段,連線點,點。
2.連線點,它是線段(或子線段)中的內容連線部分。
3.點,只有一個點的線段或者長度為0的線段。
這三種抽象事物的類UML圖如下:
這三種抽象事物的物件UML圖如下:
程式碼實現如下:
1.先定義這三個類所共同遵守的協議:Mark協議
@protocol Mark <NSObject,NSCopying> @property (nonatomic, strong) UIColor *color; @property (nonatomic, assign) CGSize size; @property (nonatomic, assign) CGPoint location; - (void)addMark:(id<Mark>)mark; - (void)removeMark:(id<Mark>)mark; - (void)removeAllMarks; - (id<Mark>)childAtIndex:(int)index; - (id<Mark>)lastChild; - (NSUInteger)count; @end
2.Stroke類實現Mark協議如下:
@interface Stroke() @property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray; @end @implementation Stroke @synthesize color,location,size; #pragma mark - 屬性操作 - (void)setLocation:(CGPoint)location {} - (CGPoint)location { if (_markArray.count) { return [[_markArray firstObject] location]; } else { return CGPointZero; } } #pragma mark - Mark操作 - (NSMutableArray<id<Mark>> *)markArray { if (!_markArray) { _markArray = @[].mutableCopy; } return _markArray; } - (void)addMark:(id<Mark>)mark { [self.markArray addObject:mark]; } - (void)removeMark:(id<Mark>)mark { //在當前節點中,就從當前節點刪除,不在當前節點,就深度查詢子節點 if ([_markArray containsObject:mark]) { [self.markArray removeObject:mark]; } else { [_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark]; } } - (void)removeAllMarks { [self.markArray removeAllObjects]; } - (id<Mark>)childAtIndex:(int)index { if (self.markArray.count == 0) { return nil; } else { return self.markArray[index]; } } - (id<Mark>)lastChild { return self.markArray.lastObject; } - (NSUInteger)count { return self.markArray.count; }
3.Vertex實現Mark協議如下:
@implementation Vertex @synthesize location; @dynamic color,size; - (instancetype)initWithLocation:(CGPoint)location { self = [super init]; if (self) { self.location = location; } return self; } #pragma mark - 屬性操作 - (UIColor *)color{return nil;} - (void)setColor:(UIColor *)color{} - (CGSize)size{return CGSizeZero;} - (void)setSize:(CGSize)size{} #pragma mark - Mark操作 - (void)addMark:(id<Mark>)mark {} - (void)removeMark:(id<Mark>)mark {} - (void)removeAllMarks {} - (id<Mark>)childAtIndex:(int)index {return nil;} - (id<Mark>)lastChild {return nil;} - (NSUInteger)count {return 0;}
4.Dot類實現Mark協議如下:
@interface Dot : Vertex @end @implementation Dot @synthesize color,size;
因為Dot類基礎自Vertex,所以物件Mark物件的操作使用父類的就好了
迭代器模式篇
迭代器模式簡介:
1.迭代器提供了一種 順序訪問聚合物件(集合)中元素的方法,而無需暴露聚合物件(集合)的底層表示和結構細節。
2. 為聚合物件(集合)配置迭代器後,遍歷集合元素的任務從集合 轉移給了迭代器物件。
3.請問啥叫迭代器模式?
答:針對抽象集合的迭代行為 而採用的設計模式,叫做迭代器模式
迭代器模式的物件圖如下:
簡單表示,迭代器持有著聚合物件
標準表示:
1.抽象聚合體Aggregate中定義了建立迭代器的介面,例項聚合類ConcreteAggregate實現建立迭代器的介面,返回自己型別的迭代器。
2.抽象迭代器Iterator定義了通用迭代方法,例項迭代器ConcreteIterator實現迭代方法介面。
迭代器模式的種類:
1.外部迭代器
由聚合物件直接將自己的迭代器返回給呼叫者,呼叫者進行靈活使用,舉例如下:
NSEnumerator *enumerator = [self enumerator]; id <Mark> mark; while (mark = [enumerator nextObject]) { [mark lastChild] }
2.內部迭代器
由聚合體提供一個迭代介面,這個迭代介面中有一個引數,該引數需要傳遞一個供聚合體內部在遍歷時呼叫的“程式碼塊”。這樣在
聚合體內部遍歷時,就將每個物件執行傳遞過來的預先定義好的函式。
舉例如下:
self.stroke = [Stroke new]; [self.stroke enumerateMarksUsingBlock:^(id<Mark> mark, BOOL *stop) { }]
迭代器模式的實際使用例子:
現在繼續使用剛才使用舉的抽象事物“線段軌跡”
這個抽象例子中包含三種模型:線段,連線點,點。
在Mark協議中定義迭代器介面,返回外部迭代器
程式碼實現如下:
Mark協議介面定義
@protocol Mark <NSObject,NSCopying> @property (nonatomic, strong) UIColor *color; @property (nonatomic, assign) CGSize size; @property (nonatomic, assign) CGPoint location; - (void)addMark:(id<Mark>)mark; - (void)removeMark:(id<Mark>)mark; - (void)removeAllMarks; - (id<Mark>)childAtIndex:(int)index; - (id<Mark>)lastChild; - (NSUInteger)count; - (instancetype)copy; //迭代器 - (NSEnumerator *)enumerator; @end;
Stroke類介面實現
@interface Stroke() @property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray; @end @implementation Stroke @synthesize color,location,size; #pragma mark - 屬性操作 - (void)setLocation:(CGPoint)location {} - (CGPoint)location { if (_markArray.count) { return [[_markArray firstObject] location]; } else { return CGPointZero; } } #pragma mark - Mark操作 - (NSMutableArray<id<Mark>> *)markArray { if (!_markArray) { _markArray = @[].mutableCopy; } return _markArray; } - (void)addMark:(id<Mark>)mark { [self.markArray addObject:mark]; } - (void)removeMark:(id<Mark>)mark { //在當前節點中,就從當前節點刪除,不在當前節點,就深度查詢子節點 if ([_markArray containsObject:mark]) { [self.markArray removeObject:mark]; } else { [_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark]; } } - (void)removeAllMarks { [self.markArray removeAllObjects]; } - (id<Mark>)childAtIndex:(int)index { if (self.markArray.count == 0) { return nil; } else { return self.markArray[index]; } } - (id<Mark>)lastChild { return self.markArray.lastObject; } - (NSUInteger)count { return self.markArray.count; } #pragma mark - 迭代器 - (NSEnumerator *)enumerator { return [[ZHFMarkEnumerator alloc] initWithMark:self]; }
在Mark協議中定義內部迭代器介面:
程式碼實現如下:
Mark協議介面定義
@protocol Mark <NSObject,NSCopying> @property (nonatomic, strong) UIColor *color; @property (nonatomic, assign) CGSize size; @property (nonatomic, assign) CGPoint location; - (void)addMark:(id<Mark>)mark; - (void)removeMark:(id<Mark>)mark; - (void)removeAllMarks; - (id<Mark>)childAtIndex:(int)index; - (id<Mark>)lastChild; - (NSUInteger)count; - (instancetype)copy; //迭代器 - (NSEnumerator *)enumerator; //內部迭代器 - (void)enumerateMarksUsingBlock:(void (^) (id <Mark> mark, BOOL *stop))block; @end;
Stroke類介面實現
@interface Stroke() @property (nonatomic, strong) NSMutableArray<id<Mark>> *markArray; @end @implementation Stroke @synthesize color,location,size; #pragma mark - 屬性操作 - (void)setLocation:(CGPoint)location {} - (CGPoint)location { if (_markArray.count) { return [[_markArray firstObject] location]; } else { return CGPointZero; } } #pragma mark - Mark操作 - (NSMutableArray<id<Mark>> *)markArray { if (!_markArray) { _markArray = @[].mutableCopy; } return _markArray; } - (void)addMark:(id<Mark>)mark { [self.markArray addObject:mark]; } - (void)removeMark:(id<Mark>)mark { //在當前節點中,就從當前節點刪除,不在當前節點,就深度查詢子節點 if ([_markArray containsObject:mark]) { [self.markArray removeObject:mark]; } else { [_markArray makeObjectsPerformSelector:@selector(removeMark:) withObject:mark]; } } - (void)removeAllMarks { [self.markArray removeAllObjects]; } - (id<Mark>)childAtIndex:(int)index { if (self.markArray.count == 0) { return nil; } else { return self.markArray[index]; } } - (id<Mark>)lastChild { return self.markArray.lastObject; } - (NSUInteger)count { return self.markArray.count; } #pragma mark - 迭代器 - (NSEnumerator *)enumerator { return [[ZHFMarkEnumerator alloc] initWithMark:self]; } - (void)enumerateMarksUsingBlock:(void (^)(id<Mark>, BOOL *stop))block { NSEnumerator *enumerator = [self enumerator]; id <Mark> mark; BOOL *stop = NO; for (id <Mark> mark in enumerator) { block(mark, &stop); if (stop) { break; } } }
熟練使用設計模式是編寫高擴充套件,高穩定,高複用,三高程式碼很重要的一項技能。願你我一同砥礪前行。
完整的專案程式碼地址如下:
目前專案還沒有完全結束,處於持續完善中...