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