摘要:,對組合對象執行的操作可以向下傳遞到葉子節點進行操作。組合模式之圖片庫圖片庫可以有選擇地隱藏或顯示圖片庫的全部或某一部分多帶帶的或是部分的。
本回內容介紹
上一回,聊了橋接模式,做了一道計算題;介一回,聊組合模式(Composite),官方描述組合模式將對象組合成樹形結構以表示“部分-整體”的層次結構,組合模式使得用戶對單個對象和組合對象的使用具有一致性。
組合模式特性這里我理了一下,就組合模式的特性而言:
1,組合模式把對象分為組合對象和葉子對象兩種。
2,組合對象和葉子對象實現同一批操作。
3,對組合對象執行的操作可以向下傳遞到葉子節點進行操作。
這樣做帶來的好處:
1,解耦,弱化類與類之間的耦合,同樣的方法得到抽離處理組合對象和葉子對象;
2,把對象組合成屬性結構的對象。
這個也是我在網上看了很多描述后做的總結。這里先看一下,然后看例子,看完例子再來看總結,應該會更有心得,來吧,開始咯。
這里需要用到之前寫過的接口類,不清楚的童鞋看看前面聊過的系列05,這里模擬一個導航菜單,如京東的一級導航,二級導航,三級導航,代碼如下:
var d = document; // 定義組合接口 var CompositeInterface = new Interface("CompositeInterface",["addChild","getChild","href"]); // 定義葉子接口 var LeafInterface = new Interface("LeafInterface",["href"]); // 定義組合類,并定義名字,類型,子集 var Composite = function(name){ this.name = name; this.type = "Composite"; this.children = []; } // 組合類的方法實現 Composite.prototype = { // 之前說過很多次的,還原指針 constructor:Composite, // 添加子集 addChild:function(child){ this.children.push(child); return this; }, // 獲取子集,這里是組合模式的關鍵 getChild:function(name){ // 定義一個結果數組 var el = []; // 添加葉子對象的方法 var addLeaf = function(item){ // 判斷傳入的類型為組合對象的情況 if(item.type==="Composite"){ // 如果為組合對象說明還有下一級,則遞歸,還記得forEach函數吧,系列01講過的,不清楚的回過頭去看看再回憶一下,這里的arguments.callee是指向函數本身的指針 item.children.forEach(arguments.callee); // 判斷如果為葉子對象,則直接添加到結果集 }else if(item.type==="Leaf"){ el.push(item); } }; // 判斷傳入的導航節點是否存在,并且是否等于當前的節點 if(name&&this.name!==name){ // 遍歷沒什么好說的 this.children.forEach(function(item){ // 判斷傳入節點為當前節點并且為組合對象則遞歸 if(item.name === name&&item.type === "Composite"){ item.children.forEach(addLeaf); } // 傳入的節點非當前節點并且是組合對象則遞歸 if(item.name !== name&&item.type === "Composite"){ item.children.forEach(arguments.callee); } // 傳入的類型如果是葉子對象,正好是調用的節點,則直接添加到結果集 if(item.name === name&&item.type === "Leaf"){ el.push(item); } }); // 這里是不傳參,或者不等于當前節點的情況 }else{ // 這里的遞歸同上 this.children.forEach(addLeaf); } return el; }, // 跳轉的方法 href:function(name){ // 獲取葉子對象 var leaves = this.getChild(name); // 遍歷并執行葉子對象的跳轉 for(var i=0;i"); } };
代碼量太多,還是把測試部分代碼分開,如下:
// 以下是測試的代碼 var n1 = new Leaf("三級導航1"); var n2 = new Leaf("三級導航2"); var n3 = new Leaf("三級導航3"); var n4 = new Leaf("三級導航4"); var n5 = new Leaf("三級導航5"); var n6 = new Leaf("三級導航6"); // 寫一個二級導航1,把前三個放入二級導航1 var nav1 = new Composite("二級導航1"); nav1.addChild(n1); nav1.addChild(n2); nav1.addChild(n3); // 寫一個二級導航2,把后三個放入二級導航2 var nav2 = new Composite("二級導航2"); nav2.addChild(n4); nav2.addChild(n5); nav2.addChild(n6); // 寫一個一級導航,把兩個二級導航放入一級導航 var nav = new Composite(); nav.addChild(nav1); nav.addChild(nav2); // 這里不傳則返回全部 nav.href("二級導航1"); // 返回三級導航1,三級導航2,三級導航3
作為第一個例子,為了便于大家理解,我基本把注釋都寫完了,把一下葉子對象的方法省去了,只寫了一個方法,更直觀方便理解。下一個例子用一個圖片庫來演示,走你。
2. 組合模式之圖片庫圖片庫可以有選擇地隱藏或顯示圖片庫的全部或某一部分(多帶帶的或是部分的)。同上面一個例子一樣,一個組合類做庫、一個葉子類則是圖片本身,如下:
var d = document; // 檢查組合對象Composite應該具備的方法 var Composite = new Interface("Composite",["add","remove","getChild"]); // 檢查組合對象GalleryItem應該具備的方法 var GalleryItem = new Interface("GalleryItem",["hide","show"]); // 實現Composite,GalleryItem組合對象類 var DynamicGallery = function(id){ // 定義子集 this.children = []; // 創建dom元素 this.el = d.createElement("div"); // 這個id跟上面個例子的name是一樣的,傳入名 this.el.id = id; // 這個className跟上面例子的type是一樣的,區分層級 this.el.className = "imageLib"; } // 組合類的方法實現 DynamicGallery.prototype = { constructor:DynamicGallery, // 實現Composite組合對象接口 add : function(child){ // 檢測接口 Interface.ensureImplements(child,Composite,GalleryItem); // 添加元素 this.children.push(child); // 添加元素到末尾的方法appendChild,不清楚的童鞋在網上搜搜哈 this.el.appendChild(child.getElement()); }, // 刪除節點 remove : function(child){ for(var node, i = 0; node = this.getChild(i); i++){ // 這里判斷是否存在,存在則刪除 if(node == child){ // 這里用數組的方法splice,不清楚的童鞋網上搜搜,比較有意思的一個方法 this.children.splice(i,1); break; } } // dom元素的刪除方法removeChild,不清楚的童鞋網上搜一下吧,嘿嘿~ this.el.removeChild(child.getElement()); }, getChild : function(i){ return this.children[i]; }, // 實現葉子對象 hide : function(){ for(var node, i = 0; node = this.getChild(i); i++){ node.hide(); } this.el.style.display = "none"; }, // 實現葉子對象 show : function(){ this.el.style.display = "block"; for(var node, i = 0; node = this.getChild(i); i++){ node.show(); } }, // 獲取當前的節點 getElement : function(){ return this.el; } } // 葉子類 var GalleryImage = function(src){ this.el = document.createElement("img"); this.el.className = "imageLeaf"; this.el.src = src; } // 葉子類的方法實現 GalleryImage.prototype = { constructor:GalleryImage, // 這里的方法都是葉子對象的,已經是葉子對象了,處于最底層的,沒有下一級了。上一個例子沒有寫,是因為盡量少寫代碼便于理解,這里我們不定義具體的實現,直接拋出就好了 add : function(){ throw new Error("This is not a instance!"); }, remove : function(){ throw new Error("This is not a instance!"); }, getChild : function(id){ // 判斷是否是當前元素,是則返回 if(this.id = id){ return this; } return null; }, // 隱藏 hide : function(){ this.el.style.display = "none"; }, // 顯示 show : function(){ this.el.style.display = "block"; }, getElement : function(){ return this.el; } }
測試部分,代碼如下:
window.onload = function(){ // 從這開始是測試部分,組合類one,用one來表示層級最高吧 var one = new DynamicGallery("one"); // 這里可以循環多張圖片來測試,隨便搜點兒圖片做測試 var item1 = new GalleryImage("./1.jpg"); var item2 = new GalleryImage("./2.jpg"); var item3 = new GalleryImage("./3.jpg"); // 添加葉子對象到頂級組合類one one.add(item1); one.add(item2); one.add(item3); // 組合類two,層級次于one two = new DynamicGallery("two"); // 同樣這里也可以循環多張圖片來測試 var item4 = new GalleryImage("./4.jpg"); var item5 = new GalleryImage("./5.jpg"); var item6 = new GalleryImage("./6.jpg"); two.add(item4); two.add(item5); two.add(item6); // 鏈式操作,后面會聊到 d.getElementById("main").appendChild(one.getElement()); one.add(two); one.show(); // 這里寫show,two里的圖片則顯示 two.hide(); }
這個例子在網上很多,這里我改了下代碼,使組合對象和葉子對象更直觀,讓這兩個類來管理圖片庫,代碼可以直接copy運行。
裝個逼咯。雙12大超市小鋪子都在搞活動,又是一陣買買買~~
遞歸這一回聊的組合模式,對于剛學JS面向對象的童鞋,頗有難度,不過不要緊,困難像彈簧,你懂的呃(的呃要快速連讀^_^)~
下面的內容,來聊聊遞歸,因為這回的組合模式用到了遞歸,剛好可以學習一下加深印象。
官方概述程序調用自身的編程技巧稱為遞歸( recursion)。
// 經典的累加,start簡寫s,end簡寫e,開始和結束的數字 function add(s,e){ // 初始化遍歷為number類型,默認值0 var num = 0; // 先加第一項 num += s; // 判斷首項小于末項則執行 if(s這里之所以用arguments.callee,好處就在于改變函數名的時候,不用再去該內部的代碼,防止出錯。
這一回,主要聊了組合模式,遞歸,其中組合模式還回憶了之前聊過的接口類,數組新特性forEach等,這回比較抽象,需要多理解~~
下一回,聊一聊狀態模式。看完點個贊,推薦推薦咯,人氣+++,動力才能+++吖,嘿嘿~~
注:此系飛狐原創,轉載請注明出處
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78317.html
本回內容介紹 上一回聊到JS中模擬接口,裝飾者模式,摻元類,分析了backbone的繼承源碼,感覺還好吧! 介一回,偶們來聊一下在JS單例模式(singleton),單例模式其實運用很廣泛,比如:jquery,AngularJS,underscore吖蝦米的都是單例模式,來吧,直接開始咯: 1. 單例模式 保證一個類只有一個實例,從全局命名空間里提供一個唯一的訪問點來訪問該對象。其實之前寫過的對象...
摘要:本回內容介紹上一回聊到數據類型,簡單的過了一遍,包括個數組新特性等,這一回來聊聊對象,結合數組來實戰一些例子,在做題中成長,記憶會更深刻,來吧,開始咯創建實例的方式有兩種使用操作符后跟構造函數飛狐使用對象字面量表示法飛狐也可以飛狐這種寫法與 本回內容介紹 上一回聊到JS數據類型,簡單的過了一遍,包括9個數組新特性等,這一回來聊聊Object對象,結合數組來實戰一些例子,在做題中成長,記...
摘要:橋接模式之特權函數特權函數,用一些具有特權的方法作為橋梁以便訪問私有空間,可以回憶一下之前的系列。連續自然數分組,計算最多組的個數將至這個連續自然數分成組使每組相加的值相等。個數組中數字最多的一組有個此時的和為。 本回內容介紹 上一回,聊了適配器模式,圖片預加載,介一回,聊橋接模式(Bridge),跟之前一樣,難度比較小,橋接模式將抽象部分與它的實現部分分離,通過橋接模式聯系彼此,同時...
摘要:本回內容介紹上一回,聊了代理模式,虛擬代理,圖片懶加載,介一回,也比較容易,適配器模式,用一個新的接口對現有類的接口進行包裝,處理類與的不匹配。這一回,主要聊了適配器模式,圖片預加載,主要還是理解下一回,聊一聊橋接模式,順便做一做計算題。 本回內容介紹 上一回,聊了代理模式,虛擬代理,圖片懶加載,介一回,也比較容易,適配器模式(Adapter),用一個新的接口對現有類的接口進行包裝,處...
摘要:本回內容介紹上一回,聊了聊狀態模式,并介紹了一下介一回,聊鏈式編程,模擬一下,再模擬一下封裝一個庫。這一回,主要聊了鏈式調用,模擬了,尤其是,希望大家能喜歡這次代碼分享。下一回,聊一聊的策略模式。 本回內容介紹 上一回,聊了聊狀態模式(State),并介紹了一下vue.js;介一回,聊鏈式編程,模擬一下jQuery,再模擬一下underscore.js,封裝一個庫。 1. 鏈式調用 (...
閱讀 1067·2021-11-23 09:51
閱讀 2412·2021-09-29 09:34
閱讀 3150·2019-08-30 14:20
閱讀 1045·2019-08-29 14:14
閱讀 3182·2019-08-29 13:46
閱讀 1077·2019-08-26 13:54
閱讀 1634·2019-08-26 13:32
閱讀 1426·2019-08-26 12:23