摘要:不同于其它靜態編程語言,實現組合模式的難點是保持樹對象與葉對象之間接口保持統一,可借助定制接口規范,實現類型約束。誤區規避組合不是繼承,樹葉對象并不是父子對象組合模式的樹型結構是一種聚合的關系,而不是。
組合模式:又叫 “部分整體” 模式,將對象組合成樹形結構,以表示 “部分-整體” 的層次結構。通過對象的多態性表現,使得用戶對單個對象和組合對象的使用具有一致性。
生活小栗子:文件目錄,DOM 文檔樹
模式特點表示 “部分-整體” 的層次結構,生成 "樹葉型" 結構;
一致操作性,樹葉對象對外接口保存一致(操作與數據結構一致);
自上而下的的請求流向,從樹對象傳遞給葉對象;
調用頂層對象,會自行遍歷其下的葉對象執行。
代碼實現樹對象和葉對象接口統一,樹對象增加一個緩存數組,存儲葉對象。執行樹對象方法時,將請求傳遞給其下葉對象執行。
// 樹對象 - 文件目錄 class CFolder { constructor(name) { this.name = name; this.files = []; } add(file) { this.files.push(file); } scan() { for (let file of this.files) { file.scan(); } } } // 葉對象 - 文件 class CFile { constructor(name) { this.name = name; } add(file) { throw new Error("文件下面不能再添加文件"); } scan() { console.log(`開始掃描文件:${this.name}`); } } let mediaFolder = new CFolder("娛樂"); let movieFolder = new CFolder("電影"); let musicFolder = new CFolder("音樂"); let file1 = new CFile("鋼鐵俠.mp4"); let file2 = new CFile("再談記憶.mp3"); movieFolder.add(file1); musicFolder.add(file2); mediaFolder.add(movieFolder); mediaFolder.add(musicFolder); mediaFolder.scan(); /* 輸出: 開始掃描文件:鋼鐵俠.mp4 開始掃描文件:再談記憶.mp3 */
CFolder 與 CFile 接口保持一致。執行 scan() 時,若發現是樹對象,則繼續遍歷其下的葉對象,執行 scan()。
JavaScript 不同于其它靜態編程語言,實現組合模式的難點是保持樹對象與葉對象之間接口保持統一,可借助 TypeScript 定制接口規范,實現類型約束。
// 定義接口規范 interface Compose { name: string, add(file: CFile): void, scan(): void } // 樹對象 - 文件目錄 class CFolder implements Compose { fileList = []; name: string; constructor(name: string) { this.name = name; } add(file: CFile) { this.fileList.push(file); } scan() { for (let file of this.fileList) { file.scan(); } } } // 葉對象 - 文件 class CFile implements Compose { name: string; constructor(name: string) { this.name = name; } add(file: CFile) { throw new Error("文件下面不能再添加文件"); } scan() { console.log(`開始掃描:${this.name}`) } } let mediaFolder = new CFolder("娛樂"); let movieFolder = new CFolder("電影"); let musicFolder = new CFolder("音樂"); let file1 = new CFile("鋼鐵俠.mp4"); let file2 = new CFile("再談記憶.mp3"); movieFolder.add(file1); musicFolder.add(file2); mediaFolder.add(movieFolder); mediaFolder.add(musicFolder); mediaFolder.scan(); /* 輸出: 開始掃描文件:鋼鐵俠.mp4 開始掃描文件:再談記憶.mp3 */透明性的安全問題
組合模式的透明性,指的是樹葉對象接口保持統一,外部調用時無需區分。但是這會帶來一些問題,如上述文件目錄的例子,文件(葉對象)下不可再添加文件,因此需在文件類的 add() 方法中拋出異常,以作提醒。
誤區規避 1. 組合不是繼承,樹葉對象并不是父子對象組合模式的樹型結構是一種 HAS-A(聚合)的關系,而不是 IS-A 。樹葉對象能夠合作的關鍵,是它們對外保持統一接口,而不是葉對象繼承樹對象的屬性方法,兩者之間不是父子關系。
2. 葉對象操作保持一致性葉對象除了與樹對象接口一致外,操作也必須保持一致性。一片葉子只能生在一顆樹上。調用頂層對象時,每個葉對象只能接收一次請求,一個葉對象不能從屬多個樹對象。
3. 葉對象實現冒泡傳遞請求傳遞由樹向葉傳遞,如果想逆轉傳遞過程,需在葉對象中保留對樹對象的引用,冒泡傳遞給樹對象處理。
4. 不只是簡單的子集遍歷調用對象的接口方法時,如果該對象是樹對象,則會將請求傳遞給葉對象,由葉對象執行方法,以此類推。不同于迭代器模式,迭代器模式遍歷并不會做請求傳導。
應用場景優化處理遞歸或分級數據結構(文件系統 - 目錄文件管理);
與其它設計模式聯用,如與命令模式聯用實現 “宏命令”。
優缺點
優點:
忽略組合對象和單個對象的差別,對外一致接口使用;
解耦調用者與復雜元素之間的聯系,處理方式變得簡單。
缺點
樹葉對象接口一致,無法區分,只有在運行時方可辨別;
包裹對象創建太多,額外增加內存負擔。
參考文章
《JavaScript 設計模式與開發實踐》
本文首發Github,期待Star!
https://github.com/ZengLingYong/blog
作者:以樂之名
本文原創,有不當的地方歡迎指出。轉載請指明出處。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/110270.html
摘要:原型式繼承利用一個空對象作為中介,將某個對象直接賦值給空對象構造函數的原型。其中表示構造函數,一個類中只能有一個構造函數,有多個會報出錯誤如果沒有顯式指定構造方法,則會添加默認的方法,使用例子如下。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導)showImg(https://segmentfault.com/img/rem...
摘要:橋接設計模式橋接模式將兩個原本不相關的類結合在一起,然后利用兩個類中的方法和屬性,輸出一份新的結果。模擬企業分組發送短信需求公司現在需要按分組臨時工正式工管理層等以多種形式微博等給員工發送通知。 橋接設計模式 橋接模式:將兩個原本不相關的類結合在一起,然后利用兩個類中的方法和屬性,輸出一份新的結果。 案例 模擬毛筆 需求:現在需要準備三種粗細(大中小),并且有五種顏色的比 如果使用蠟...
摘要:首先推薦幾個正則表達式編輯器正則表達式是一種查找以及字符串替換操作。此表所列的常用正則表達式,除個別外均未在前后加上任何限定,請根據需要,自行處理。例如對而言,則采用一對引號來確定正則表達式的邊界。 這篇文章本來很早就要寫的,拖了挺久的,現在整理下,供大家學習交流哈! 基本概念 正則表達式是一種文本模式,包括普通字符(例如,a 到 z 之間的字母)和特殊字符(稱為元字符)。模式描述在搜...
摘要:適配器模式應用場景適配器模式應用場景修改已使用的接口某個已經投產中的接口需要修改,這時候使用適配器最好。適配器模式適配器模式是一種事后的補救策略。1、什么是適配器模式?Convert the interface of a class into another interface clients expect.Adapter lets classes work together that co...
摘要:綜上所述有原型鏈繼承,構造函數繼承經典繼承,組合繼承,寄生繼承,寄生組合繼承五種方法,寄生組合式繼承,集寄生式繼承和組合繼承的優點于一身是實現基于類型繼承的最有效方法。 一、前言 繼承是面向對象(OOP)語言中的一個最為人津津樂道的概念。許多面對對象(OOP)語言都支持兩種繼承方式::接口繼承 和 實現繼承 。 接口繼承只繼承方法簽名,而實現繼承則繼承實際的方法。由于js中方法沒有簽名...
閱讀 1951·2021-09-07 09:59
閱讀 2519·2019-08-29 16:33
閱讀 3688·2019-08-29 16:18
閱讀 2848·2019-08-29 15:30
閱讀 1677·2019-08-29 13:52
閱讀 2035·2019-08-26 18:36
閱讀 529·2019-08-26 12:19
閱讀 693·2019-08-23 15:23