iOS設計模式之組合模式


大家好久不見喲!忙了一個月終于可以回歸到設計模式了。前幾天肥羊蜀黍在玩室友鵬鵬的電腦,感嘆現在的年輕人真是精力旺盛,代碼寫得牛P就算了,還如此勤奮的學習各國文化和語言,他的DEF盤放滿各種學習資料,什么”日語學習“、”歐美風情“、“日韓文化”,我對日韓文化也頗感興趣,于是就點開了看看,怎么包了n層文件夾,點到最后....畫面女人看了臉紅,男人看了血脈噴張。好了,警察叔叔來了,要趕緊溜了,畢竟還是無證駕駛!!!

一、組合模式的概念

先來一段官方概念:組合多個對象形成樹形結構以表示“整體-部分”的結構層次。組合模式對單個對象(即葉子對象)和組合對象(即容器對象)的使用具有一致性。

二、案例實現

這句官方解釋也是有點抽象,為了能讓大家更好地理解組合模式,今天就以我們非常熟悉的電腦文件作為故事背景!!!管理文件的時候,我們不難發現,文件夾和文件的關系就像一棵“樹”,如下圖


文件路徑示例

1、非組合模式演示

看完這個圖,我們再構思一下架構,此時,鵬鵬一拍桌子說是這樣的,如下圖:


鵬鵬還順帶用5分鐘把代碼寫出來了,然而我陷入了沉思...通常來說,業務邏輯關系相對簡單、類之間的繼承關系少的時候可以用上圖的架構,但如果繼承關系有n層呢?如果項目有多個層次節點呢?如果像鵬鵬那么調皮喜歡把文件用n個文件夾包著呢?那咋辦?!此時的我開始抓狂,進而不知所措,想想好像也只能殺個室友祭天了!!!(此時鵬鵬在墻角瑟瑟發抖)

2、組合模式演示

還好組合模式的出現拯救了鵬鵬,組合模式分為安全組合模式和透明組合模式,首先介紹比較常用而且比較推崇的安全組合模式,UML如下圖:

2.1 安全組合模式

看了這個UML鵬鵬松了口氣,小命得保。工作量看著減少很多,接口沒有了,改為了抽象類,方法直接放在實現類中,好精簡有木有!用Component基類封裝一些通用的方法和屬性,Composite(整體)和Leaf(部分)繼承基類,分別實現各自的方法,使有復雜層次關系或樹狀結構的架構簡化為只有整體和部分兩大塊。接下來看看代碼演示:

Component.h
//通用屬性
@property (nonatomic,copy) NSString *name;
@property (nonatomic,assign) float size;
//通用方法
- (instancetype)initWithName:(NSString *)name andSize:(float)size;
- (NSString *) getInfo;
Component.m
//方法實現
- (void)addFile:(Component *)file {
    [self.sububdirectory addObject:file];
}

- (NSArray *)getSubdirectory {
    return self.sububdirectory;
}

- (NSMutableArray *)sububdirectory {
    if (!_sububdirectory) {
        _sububdirectory = [NSMutableArray array];
    }
    return _sububdirectory;
}
//使用場景
- (void) compositePattern {
    //d_disk 作為root
    //鵬鵬的D盤學習資料最多,我們就來剖析D盤吧...嘻嘻嘻~~wow!!!1T學習資料哦
    Composite *d_disk = [[Composite alloc] initWithName:@"鵬鵬的D盤" andSize:1024];
    //鵬鵬真勤奮,這么多類型的學習資料
    //這里暫且忽略中間包的n層文件夾吧
    Composite *language_Jan = [[Composite alloc] initWithName:@"日語學習" andSize:0.5];
    Composite *culture_Korea = [[Composite alloc] initWithName:@"韓國風俗文化" andSize:0.25];
    //這部小電影...知道文件名叫啥不?so easy...耳熟能詳!跟著蜀黍大聲讀“雅蠛蝶!!!”
    Leaf *video_Jan = [[Leaf alloc] initWithName:@"やめて" andSize:0.5];
    //其他小電影名字太辣眼睛,這里就不做詳細介紹(車牌還是找吾力鵬鵬要)
    Leaf *video_Jan1 = [[Leaf alloc] initWithName:@"小電影1" andSize:0.5];
    Leaf *video_Jan2 = [[Leaf alloc] initWithName:@"小電影2" andSize:0.2];
    Leaf *pic_Korea1 = [[Leaf alloc] initWithName:@"小圖片1" andSize:0.02];
    Leaf *pic_Korea2 = [[Leaf alloc] initWithName:@"小圖片2" andSize:0.01];
    //開始組裝樹
    [d_disk addFile:language_Jan];
    [d_disk addFile:culture_Korea];
    [language_Jan addFile:video_Jan];
    [language_Jan addFile:video_Jan1];
    [language_Jan addFile:video_Jan2];
    [culture_Korea addFile:pic_Korea1];
    [culture_Korea addFile:pic_Korea2];
    //遍歷硬盤里面的各個文件(小電影)
    NSLog(@"%@",[d_disk getInfo]);
    [self cp_traverseSubdiretory:[d_disk getSubdirectory]];
}

- (void) cp_traverseSubdiretory:(NSArray *)directory {
    for (id obj in directory) {
        if ([obj isKindOfClass:[Composite class]]) {
            Composite *folder = obj;
            NSLog(@"%@",[folder getInfo]);
            //遞歸遍歷
            [self cp_traverseSubdiretory:[folder getSubdirectory]];
        }else{
            Leaf *file = obj;
            NSLog(@"%@",[file getInfo]);
        }
    }
}

運行結果如下:

組合模式demo[1295:17972] name:鵬鵬的D盤 | size:1024.0
組合模式demo[1295:17972] name:日語學習 | size:0.5
組合模式demo[1295:17972] name:やめて | size:0.5
組合模式demo[1295:17972] name:小電影1 | size:0.5
組合模式demo[1295:17972] name:小電影2 | size:0.200000
組合模式demo[1295:17972] name:韓國風俗文化 | size:0.25
組合模式demo[1295:17972] name:小圖片1 | size:0.02
組合模式demo[1295:17972] name:小圖片2 | size:0.01

上述就是安全組合模式的簡單演示。接下來就是透明組合模式的介紹。

2.2透明組合模式

透明組合模式和安全組合模式的區別不大,只有一點,Leaf和Composite的方法全部在基類Component實現,UML如下:


由于篇幅問題,透明組合模式的代碼演示就不放啦!

要詳細了解請到詳細代碼演示查看

三、總結分析

1、安全組合模式

  • 優點:
    安全組合模式是由基類管理通用方法,Leaf和Composite各自管理擁有的方法,能確保各個類都只有職責范圍內的方法,比如文件夾只會有添加文件的方法,不可能有打開文件的功能,視頻文件也只有播放視頻的功能,不可能有添加文件的功能。
  • 缺點:
    在代碼演示部分可以看到,在安全組合模式下需要對類進行判斷,如果繼承基類的子類數目多,就會造成過多if-else的判斷,影響代碼質量。如果子類數量較多的時候應慎重考慮。

2、透明組合模式

  • 優點:
    在透明組合模式下,由基類統一管理所有方法,因此不需要進行類型判斷轉換。該模式針對抽象類編程,上層(抽象基類)的調用不依賴下層(子類),基本遵循依賴倒置原則,方便擴展。
  • 缺點:
    透明模式的缺點也十分明顯,由于方法由基類統一管理,可能會出現類持有了職責范圍外的方法,例如一個文件類具有添加文件夾的方法,這顯然是不合理的,因此在子類中我們會重寫子類不應該擁有的方法,通常會重寫為空方法或拋出異常處理,這一定程度上違反了里氏替換原則,還一定程度加大了工作量。
  • 總體來說,組合模式的優缺點都十分突出且極端,在使用前要結合需求進行分析,靈活運用,盲目套用設計模式反而會給自己挖坑哦!
一個月沒寫文章了,學習的同時一定要懂得總結,而寫作就是一次對自己學習結果的檢驗,今后要把總結和寫作作為一種興趣一種習慣。為自己的目標干巴爹!!!
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容