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、透明組合模式

  • 優點:
    在透明組合模式下,由基類統一管理所有方法,因此不需要進行類型判斷轉換。該模式針對抽象類編程,上層(抽象基類)的調用不依賴下層(子類),基本遵循依賴倒置原則,方便擴展。
  • 缺點:
    透明模式的缺點也十分明顯,由于方法由基類統一管理,可能會出現類持有了職責范圍外的方法,例如一個文件類具有添加文件夾的方法,這顯然是不合理的,因此在子類中我們會重寫子類不應該擁有的方法,通常會重寫為空方法或拋出異常處理,這一定程度上違反了里氏替換原則,還一定程度加大了工作量。
  • 總體來說,組合模式的優缺點都十分突出且極端,在使用前要結合需求進行分析,靈活運用,盲目套用設計模式反而會給自己挖坑哦!
一個月沒寫文章了,學習的同時一定要懂得總結,而寫作就是一次對自己學習結果的檢驗,今后要把總結和寫作作為一種興趣一種習慣。為自己的目標干巴爹!!!
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,763評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,238評論 3 428
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,823評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,604評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,339評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,713評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,712評論 3 445
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,893評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,448評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,201評論 3 357
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,397評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,944評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,631評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,033評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,321評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,128評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,347評論 2 377

推薦閱讀更多精彩內容