設計模式之組合模式

組合模式

組合模式,將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。掌握組合模式的重點是要理解清楚 “部分/整體” 還有 ”單個對象“ 與 "組合對象" 的含義。
組合模式可以讓客戶端像修改配置文件一樣簡單的完成本來需要流程控制語句來完成的功能。
經典案例:系統目錄結構,網站導航結構等。

模式作用:

  1. 你想表示對象的部分-整體層次結構時
  2. 你希望用戶忽略組合對象和單個對象的不同,用戶將統一地使用組合結構中的所有對象(方法)

注意事項:

  1. 該模式經常和裝飾者模式一起使用,它們通常有一個公共的父類(也就是原型),因此裝飾必須支持具有add,remove,getChild操作的component接口

例子:

文件夾和文件之間的關系,非常適合用組合模式來描述.文件夾里既可以包含文件,又可以包含其他文件夾,最終可能組合成一棵樹,組合模式在文件夾的應用中有一下兩層好處.
例如,我在同事的移動硬盤里找到了一些電子書,想把它們復制到F盤中的學習資料文件夾.在復制這些電子書的時候,我并不需要考慮這批文件的類型,不管它們是單獨的電子書還是被放在了文件夾中.組合模式讓Ctrl+V,Ctrl+C成為了一個統一的操作.
當我用殺毒軟件掃描該文件夾時,往往不會關心里面有多少文件和子文件夾,組合模式使得我們只需要操作最外層的文件夾進行掃描
現在我們來編寫代碼,首先分別定義好文件夾Folder和文件File這兩個類.見如下代碼:

/***********Folder***********/
var Folder=function(name){
  this.name=name;
  this.files=[];
}
Folder.prototype.add=function(file){
  this.files.push(file)
}
Folder.prototype.scan=function(){
  console.log("開始掃描文件夾:"+this.name);
  for(var i=0;file=this.files[i];i++){
    file.scan();
  }
}
/***********File***********/
var File=function(name){
  this.name=name;
}
File.prototype.add=function(){
  throw new Error("文件下面不能添加文件");
}
File.prototype.scan=function(){
  console.log("開始掃描文件:"+this.name);
}

接下來創建一些文件夾和文件對象,并且讓它們組合成一棵樹,這棵樹就是我們F盤里的現有文件目錄結構:

var folder=new Folder("學習資料");
var folder1=new Folder("JavaScript");
var folder2=new Folder("JQuery");
var file1=new File("JavaScript設計模式與開發實踐")
var file2=new File("精通JQuery");
var file3=new File("重構與模式");
folder1.add(file1);
folder2.add(file2);
folder.add(folder1);
folder.add(folder2);
folder.add(file3);

現在的需求是把移動硬盤里的文件和文件夾都復制到這棵樹中,假設我們已經得到了這些文件對象:

var folder3=new Folder("Nodejs");
var file4=new File("深入淺出Node.js");
folder3.add(file4);
var file5=new File("JavaScript語言精髓與編程實踐");
folder.add(folder3);
folder.add(file5);

通過這個例子,我們再次看到客戶是如何同等對待組合對象和葉對象.在添加一批文件的操作過程中,客戶不用分辨它們到底是文件還是文件夾.新增加的文件和文件夾能夠很容易地添加到原來的樹結構中,和樹里已有的對象一起工作
我們改變了樹的結構,添加了新的數據,卻不用修改任何一句原有的代碼,這是符合開放-封閉原則的.
運用了組合模式之后,掃描整個文件夾的操作也是輕而易舉的,我們只需要操作樹的最頂端對象

folder.scan()

執行結果如下如所示:


一些值得注意的地方

  1. 組合模式不是父子關系
    組合模式的樹形結構容易讓人誤以為組合對象和葉對象是父子關系,這是不正確的.
    組合模式是一種HAS-A(聚合)的關系,而不是IS-A.組合對象包含一組葉對象,但Leaf并不是composite的子類.組合對象把請求委托給它所包含的所有葉對象,它們能夠合作的關鍵是擁有相同的接口.
  2. 和葉對象操作的一致性
    組合模式除了要求組合對象和葉對象擁有相同的接口之外,還有一個必要條件,就是對一組葉對象的操作必須具有一致性.
    比如公司要給全體員工發放元旦的過節費1000塊,這個場景可以運用組合模式,但如果公司給今天過生日的員工發送一封生日祝福的郵件,組合模式在這里就沒有用武之地了,除非先把今天過生日的員工挑選出來.只有用一致的方式對待列表中的每個葉對象的時候,才適合使用組合模式
  3. 雙向映射關系
    發放過節費的通知步驟是從公司到各個部門,再到各個小組,最后到每個員工的郵箱里.這本身是個組合模式的好例子,但要考慮的一種情況是,也許某些員工屬于多個組織架構.比如某位架構師既隸屬于開發組,又隸屬于架構組,對象之間的關系并不是嚴格意義上的層次結構,在這種情況下,是不適合使用組合模式的額,該架構師很可能會收到兩份過節費.
    這種復合情況下我們必須給父節點和子節點建立雙向映射關系,一個簡單的方法是給小組和員工對象都增加集合來保存對方的引用.但是這種相互間的引用相當復雜,而且對象之間產生了過多的耦合性,修改或者刪除一個對象都變得困難,此時我們可以引入中介者模式來管理這些對象
  4. 用職責鏈模式來提高組合模式性能
    在組合模式中,如果樹的結構比較復雜,節點數量很多,在遍歷樹的過程中,性能方面也許表現得不夠理想.有時候我們確實可以借助一些技巧,在實際操作中避免遍歷整棵樹,有一種現成的方案是借助職責鏈模式.職責鏈模式一般需要我們手動去設置鏈條,但在組合模式中,父對象和自對象之間實際上形成了天然的職責鏈.讓請求順著鏈條從父對象往子對象傳遞,或者是反過來從子對象往父對象傳遞,直到遇到可以處理該請求的對象為止,這也是職責鏈模式的經典運用場景之一.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容