JavaScript設(shè)計(jì)模式開(kāi)發(fā)中組合模式的使用教程
我們平時(shí)開(kāi)發(fā)過(guò)程中,一定會(huì)遇到這種情況:同時(shí)處理簡(jiǎn)單對(duì)象和由簡(jiǎn)單對(duì)象組成的復(fù)雜對(duì)象,這些簡(jiǎn)單對(duì)象和復(fù)雜對(duì)象會(huì)組合成樹(shù)形結(jié)構(gòu),在客戶端對(duì)其處理的時(shí)候要保持一致性。比如電商網(wǎng)站中的產(chǎn)品訂單,每一張產(chǎn)品訂單可能有多個(gè)子訂單組合,比如操作系統(tǒng)的文件夾,每個(gè)文件夾有多個(gè)子文件夾或文件,我們作為用戶對(duì)其進(jìn)行復(fù)制,刪除等操作時(shí),不管是文件夾還是文件,對(duì)我們操作者來(lái)說(shuō)是一樣的。在這種場(chǎng)景下,就非常適合使用組合模式來(lái)實(shí)現(xiàn)。
基本知識(shí)
組合模式:將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模式使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
組合模式主要有三個(gè)角色:
(1)抽象組件(Component):抽象類(lèi),主要定義了參與組合的對(duì)象的公共接口
(2)子對(duì)象(Leaf):組成組合對(duì)象的最基本對(duì)象
(3)組合對(duì)象(Composite):由子對(duì)象組合起來(lái)的復(fù)雜對(duì)象
理解組合模式的關(guān)鍵是要理解組合模式對(duì)單個(gè)對(duì)象和組合對(duì)象使用的一致性,我們接下來(lái)說(shuō)說(shuō)組合模式的實(shí)現(xiàn)加深理解。
組合模式算是為在頁(yè)面動(dòng)態(tài)創(chuàng)建UI量身定做的,你可以只使用一條命=命令為許多對(duì)象初始化一些復(fù)雜的或者遞歸的操作.組合模式提供了兩個(gè)有點(diǎn):
(1)允許你將一組對(duì)象當(dāng)成特定的對(duì)象.組合對(duì)象(A composite)和組成它的子對(duì)象實(shí)現(xiàn)相同的操作.對(duì)組合對(duì)象執(zhí)行某一個(gè)操作將會(huì)使該對(duì)象下的所有子對(duì)象執(zhí)行相同的操作.因此你不僅可以無(wú)縫的替換單個(gè)對(duì)象為一組對(duì)象集合,反過(guò)來(lái)也一樣.這些獨(dú)立的對(duì)象之間即所謂松散耦合的.
(2)組合模式會(huì)將子對(duì)象集組合成樹(shù)結(jié)構(gòu)并且允許遍歷整個(gè)樹(shù).這樣可以隱藏內(nèi)部實(shí)現(xiàn)并且允許你以任意的方式組織子對(duì)象.這個(gè)對(duì)象(組合對(duì)象)的任何代碼將不會(huì)依賴(lài)內(nèi)部子對(duì)象的實(shí)現(xiàn).
組合模式的實(shí)現(xiàn)
(1)最簡(jiǎn)單的組合模式
HTML文檔的DOM結(jié)構(gòu)就是天生的樹(shù)形結(jié)構(gòu),最基本的元素醉成DOM樹(shù),最終形成DOM文檔,非常適用適用組合模式。
我們常用的jQuery類(lèi)庫(kù),其中組合模式的應(yīng)用更是頻繁,例如經(jīng)常有下列代碼實(shí)現(xiàn):
$(".test").addClass("noTest").remove("test");
這句簡(jiǎn)單的代碼就是獲取class包含test的元素,然后進(jìn)行addClass和removeClass處理,其中不論$(“.test”)是一個(gè)元素,還是多個(gè)元素,最終都是通過(guò)統(tǒng)一的addClass和removeClass接口進(jìn)行調(diào)用。
我們簡(jiǎn)單模擬一下addClass的實(shí)現(xiàn):
var addClass = function (eles, className) { if (eles instanceof NodeList) { for (var i = 0, length = eles.length; i < length; i++) { eles[i].nodeType === 1 && (eles[i].className += (' ' + className + ' ')); } } else if (eles instanceof Node) { eles.nodeType === 1 && (eles.className += (' ' + className + ' ')); } else { throw "eles is not a html node"; } } addClass(document.getElementById("div3"), "test"); addClass(document.querySelectorAll(".div"), "test");
這段代碼簡(jiǎn)單的模擬了addClass的實(shí)現(xiàn)(暫不考慮兼容性和通用性),很簡(jiǎn)單地先判斷節(jié)點(diǎn)類(lèi)型,然后根據(jù)不同類(lèi)型添加className。對(duì)于NodeList或者是Node來(lái)說(shuō),客戶端調(diào)用都是同樣的使用了addClass這個(gè)接口,這個(gè)就是組合模式的最基本的思想,使部分和整體的使用具有一致性。
(2)典型的例子
前面我們提到一個(gè)典型的例子:產(chǎn)品訂單包含多個(gè)產(chǎn)品子訂單,多個(gè)產(chǎn)品子訂單組成一個(gè)復(fù)雜的產(chǎn)品訂單。由于Javascript語(yǔ)言的特性,我們將組合模式的三個(gè)角色簡(jiǎn)化成2個(gè)角色:
(1)子對(duì)象:在這個(gè)例子中,子對(duì)象就是產(chǎn)品子訂單
(2)組合對(duì)象:這里就是產(chǎn)品的總訂單
假設(shè)我們開(kāi)發(fā)一個(gè)旅游產(chǎn)品網(wǎng)站,其中包含機(jī)票和酒店兩種子產(chǎn)品,我們定義了子對(duì)象如下:
function FlightOrder() { } FlightOrder.prototyp.create = function () { console.log("flight order created"); } function HotelOrder() { } HotelOrder.prototype.create = function () { console.log("hotel order created"); }
上面的代碼定義了兩個(gè)類(lèi):機(jī)票訂單類(lèi)和酒店訂單類(lèi),每個(gè)類(lèi)都有各自的訂單創(chuàng)建方法。
接下來(lái)我們創(chuàng)建一個(gè)總訂單類(lèi):
function TotalOrders() { this.orderList = []; } TotalOrders.prototype.addOrder = function (order) { this.orderList.push(order); } TotalOrders.prototype.create = function (order) { for (var i = 0, length = this.orderList.length; i < length; i++) { this.orderList[i].create(); } }
這個(gè)對(duì)象主要有3個(gè)成員:訂單列表,添加訂單的方法,創(chuàng)建訂單的方法。
在客戶端使用的時(shí)候如下:
var flight = new FlightOrder(); flight.create(); var orders = new TotalOrders(); orders.addOrder(new FlightOrder()); orders.addOrder(new HotelOrder()); orders.create();
客戶端調(diào)用展示了兩種方式,一種是單一的創(chuàng)建機(jī)票訂單,一種是創(chuàng)建多張訂單,但最終都是通過(guò)create方法進(jìn)行創(chuàng)建,這就是一個(gè)很典型的組合模式的應(yīng)用場(chǎng)景。
總結(jié)
組合模式并不難理解,它主要解決的是單一對(duì)象和組合對(duì)象在使用方式上的一致性問(wèn)題。如果對(duì)象具有明顯的層次結(jié)構(gòu)并且想要統(tǒng)一地使用它們,這就非常適合使用組合模式。在Web開(kāi)發(fā)中,這種層次結(jié)構(gòu)非常常見(jiàn),很適合使用組合模式,尤其是對(duì)于JS來(lái)說(shuō),不用拘泥于傳統(tǒng)面向?qū)ο笳Z(yǔ)言的形式,靈活地利用JS語(yǔ)言的特性,達(dá)到對(duì)部分和整體使用的一致性。
(1)使用組合模式的場(chǎng)景
在遇到下面兩種情況的時(shí)候才使用組合模式
A.含有某種層級(jí)結(jié)構(gòu)的對(duì)象集合(具體結(jié)構(gòu)在開(kāi)發(fā)過(guò)程中無(wú)法確定)
B.希望對(duì)這些對(duì)象或者其中的某些對(duì)象執(zhí)行某種操作
(2)組合模式的缺點(diǎn)
因?yàn)榻M合對(duì)象的任何操作都會(huì)對(duì)所有的子對(duì)象調(diào)用同樣的操作,所以當(dāng)組合的結(jié)構(gòu)很大時(shí)會(huì)有性能問(wèn)題。還有就是使用組合模式封裝HTML時(shí)要選擇合適的標(biāo)簽,比如table就不能用于組合模式,葉子節(jié)點(diǎn)不明顯
- JavaScript適配器模式詳解
- javascript設(shè)計(jì)模式之Adapter模式【適配器模式】實(shí)現(xiàn)方法示例
- JavaScript設(shè)計(jì)模式之適配器模式介紹
- 深入理解JavaScript系列(39):設(shè)計(jì)模式之適配器模式詳解
- 詳解JavaScript實(shí)現(xiàn)設(shè)計(jì)模式中的適配器模式的方法
- javascript設(shè)計(jì)模式 – 適配器模式原理與應(yīng)用實(shí)例分析
- JavaScript設(shè)計(jì)模式學(xué)習(xí)之適配器模式
- JavaScript 設(shè)計(jì)模式之組合模式解析
- JavaScript組合模式學(xué)習(xí)要點(diǎn)
- 設(shè)計(jì)模式中的組合模式在JavaScript程序構(gòu)建中的使用
- javascript設(shè)計(jì)模式 – 組合模式原理與應(yīng)用實(shí)例分析
- javascript適配器模式和組合模式原理與實(shí)現(xiàn)方法詳解
相關(guān)文章
有關(guān)于JS構(gòu)造函數(shù)的重載和工廠方法
有關(guān)于JS構(gòu)造函數(shù)的重載和工廠方法,對(duì)此有需要的朋友,參考一下。2013-04-04javascript之Boolean類(lèi)型對(duì)象
本文主要介紹javascript中的Boolean類(lèi)型對(duì)象,Boolean對(duì)象非常簡(jiǎn)單,卻非常有用,希望能給大家做一個(gè)參考。2016-06-06JavaScript 基礎(chǔ)篇之對(duì)象、數(shù)組使用介紹(三)
對(duì)象我們?cè)谇懊嬉埠?jiǎn)單介紹過(guò),它是一種將多個(gè)數(shù)據(jù)值集中在一個(gè)單元的東西,使用名字來(lái)存取,它是一個(gè)無(wú)序的屬性集合2012-04-04javascript中的3種繼承實(shí)現(xiàn)方法
這篇文章主要介紹了javascript中的3種繼承實(shí)現(xiàn)方法,包括使用Object.create實(shí)現(xiàn)類(lèi)式繼承、使用utilities工具包自帶的util.inherites、使用extends關(guān)鍵字,非常的實(shí)用,希望對(duì)大家了解javascript繼承能夠有所幫助2016-01-01Node.js生成HttpStatusCode輔助類(lèi)發(fā)布到npm
本篇文章小編為大家介紹利用Node.js為Node.js生成HttpStatusCode輔助類(lèi)并發(fā)布到npm,有需要的朋友可以參考一下2013-04-04