設計模式應用場景之Model設計中可以用到的設計模式

滴水微瀾發表於2018-12-22
在開發中,不同的場景適用不同的設計模式。對於開發建模方面,可以根據模型的抽象型別設計成簡單屬性模式和複雜組合模式。
因為組合模式中的屬性為多種型別物件,可操作性也比較靈活。
而針對這種複雜資料結構,有兩種設計模式可以使用:
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;
        }
    }
}
熟練使用設計模式是編寫高擴充套件,高穩定,高複用,三高程式碼很重要的一項技能。願你我一同砥礪前行。
完整的專案程式碼地址如下:
目前專案還沒有完全結束,處於持續完善中...
 

相關文章