摘要:橋接實(shí)現(xiàn)的時(shí)候橋接模式非常有用可能正是由于這個(gè)該模式使用地不夠廣泛在設(shè)計(jì)時(shí)該模式可以弱化與使用它的類(lèi)和對(duì)象之間的耦合該模式的作用在于將抽象與其實(shí)現(xiàn)隔離開(kāi)讓他們獨(dú)立變化而且對(duì)于事件驅(qū)動(dòng)編程有許多好處有以及其他基于動(dòng)作的方法無(wú)論它們是用來(lái)創(chuàng)建鼓
橋接
實(shí)現(xiàn) API 的時(shí)候,橋接模式非常有用,可能正是由于這個(gè),該模式使用地不夠廣泛.在設(shè)計(jì) js API 時(shí),該模式可以弱化API 與使用它的類(lèi)和對(duì)象之間的耦合. 該模式的作用在于**將抽象與其實(shí)現(xiàn)隔離開(kāi),讓他們獨(dú)立變化**.而且對(duì)于事件驅(qū)動(dòng)編程有許多好處. js API有 getter, setter, requester 以及其他基于動(dòng)作的方法.無(wú)論它們是用來(lái)創(chuàng)建 Web 鼓舞 API 還是普通 accessor 和 mutator.在實(shí)現(xiàn)過(guò)程中橋接模式都有助于保持 API 代碼的簡(jiǎn)潔.事件監(jiān)聽(tīng)器
最常見(jiàn)的應(yīng)用場(chǎng)合之一是事件監(jiān)聽(tīng)回調(diào).假設(shè)有一個(gè) API 函數(shù) getBeerById, 他根據(jù)一個(gè)標(biāo)識(shí)符返回有關(guān)啤酒的信息.
addEvent(ele, "click", getBeerById); function getBeerById(e) { var id = this.id; asyncRequest("GET", "beer.url?id=" + id, function(resp) { // Callback response. console.log("Requested Beer: " + resp.responseText); }); }
這個(gè) API 只能工作在瀏覽器中,根據(jù)事件監(jiān)聽(tīng)器回調(diào)函數(shù)的機(jī)制,事件對(duì)象自然會(huì)被作為第一個(gè)參數(shù)傳遞給這個(gè)函數(shù),在本例中沒(méi)有使用這個(gè)參數(shù),只是從 this 對(duì)象獲取 id.那么如果在命令行環(huán)境運(yùn)行它就失效不起作用.
function getBeerById(id, callback) { // Make request for beer by ID, then return the beer data. asyncRequest("GET", "beer.url?id=" + id, function (resp) { // callback reponse callback(resp.responseText); }); } addEvent(ele, "click", getBeerByIdBridge); function getBeerByIdBridge(e) { getBeerById(this.id, function (beer) { console.log("Requested Beer: " + beer); }); }
這樣就只針對(duì)接口而不是實(shí)現(xiàn)進(jìn)行編程,用橋接模式把抽象隔離開(kāi)來(lái).
有了這層橋接元素,API 的適用范圍大大拓寬,現(xiàn)在的 getBeerById 沒(méi)有和事件對(duì)象綁定在一起,可以在單元測(cè)試中運(yùn)行該 API,只需提供一個(gè) ID 和對(duì)調(diào)函數(shù).現(xiàn)在可以在命令行環(huán)境運(yùn)行這個(gè)接口.
除了在事件回調(diào)函數(shù)與接口之間進(jìn)行橋接外,橋接模式還可以用連接公開(kāi)的 API代碼和私有的實(shí)現(xiàn)代碼.另外,還可以連接多個(gè)類(lèi).從類(lèi)的角度看,意味著把接口作為公開(kāi)的代碼編寫(xiě),把類(lèi)的實(shí)現(xiàn)作為私有代碼編寫(xiě).
可以使用一些特權(quán)方法來(lái)做橋梁以便訪問(wèn)私有變量空間.第3章已經(jīng)見(jiàn)到過(guò).
var Public = function () { var secretNum = 3; this.privilegedGetter = function () { return secretNum; }; }; var p = new Public(); var data = p.privilegedGetter();
連接多個(gè)類(lèi):
var Class1 = function (a, b, c) { this.a = a; this.b = b; this.c = c; }; var Class2 = function (d) { this.d = d; } var BridgeClass = function (a, b, c, d) { this.one = new Class1(a, b, c); this.two = new Class2(d); }
在這里,橋接類(lèi)是一個(gè)門(mén)面類(lèi),不同的是橋接模式能夠讓Class1和 Class2獨(dú)立于 BridgeClass 而發(fā)生變化,和門(mén)面類(lèi)不同.
適用場(chǎng)合事件驅(qū)動(dòng)編程必備.不過(guò)我們喜歡事件驅(qū)動(dòng)開(kāi)發(fā)的函數(shù)式風(fēng)格,卻忘了編寫(xiě)接口.判斷什么時(shí)候是用橋接模式很簡(jiǎn)單:
$("#example-id").on("click", function () { new RichTextEditor(); })l
現(xiàn)在沒(méi)法看出編輯器要顯示在哪,有什么配置項(xiàng),還有如何修改.要做的是讓接口"可橋接"(可適配)...
還有就是之前講到的特權(quán)函數(shù)用來(lái)訪問(wèn)私有數(shù)據(jù).
利讓 API 更強(qiáng)壯,提高組件的模塊化程度.把抽象和其實(shí)現(xiàn)隔離開(kāi),有助于獨(dú)立管理,而且Bug 更容易查找.
弊每使用一個(gè)橋接元素都要增加一次函數(shù)調(diào)用,提高系統(tǒng)復(fù)雜度,影響性能,不要濫用,舉例來(lái)說(shuō),如果一個(gè)橋接函數(shù)被用于連接兩個(gè)函數(shù),但是其中某個(gè)函數(shù)根本不會(huì)在橋接函數(shù)之外被調(diào)用,那么該橋接函數(shù)可以不用.
----------next part----------
組合同一條命令在多個(gè)對(duì)象上引發(fā)復(fù)雜或者遞歸的操作.
兩大好處:
用同樣的方法處理對(duì)象集合和其中的特定子對(duì)象.組合對(duì)象 composite 和組成它的對(duì)象實(shí)現(xiàn)了同批操作.是一種向下傳遞的操作性質(zhì).
把一批子對(duì)象組織成樹(shù)形結(jié)構(gòu),使整棵樹(shù)都可以被遍歷.所有組合對(duì)象都實(shí)現(xiàn)了一個(gè)用來(lái)獲取子對(duì)象的方法.
組合對(duì)象的結(jié)構(gòu)組合對(duì)象的層次體系中有兩種類(lèi)型的對(duì)象:葉對(duì)象和組合對(duì)象,是一個(gè)遞歸定義:一個(gè)組合對(duì)象由一些別的組合對(duì)象和葉對(duì)象組成.只有葉對(duì)象不再包含子對(duì)象,它是組合對(duì)象中最基本的元素,也落實(shí)了各種操作.(樹(shù)是數(shù)據(jù)結(jié)構(gòu)中較為基本的概念,這里的概念應(yīng)該不難理解的)
使用必須同時(shí)具備兩個(gè)條件:
存在一批組織成某種層次體系的對(duì)象
希望對(duì)這批對(duì)象或者其中一部分對(duì)象進(jìn)行一個(gè)共同操作.
組合模式擅長(zhǎng)于對(duì)大批對(duì)象進(jìn)行操作.組織這類(lèi)對(duì)象并把操作從一個(gè)層次向下一個(gè)層次傳遞,可以弱化對(duì)象間的耦合并且可以互換的使用一些類(lèi)或者實(shí)例.
要求創(chuàng)建一個(gè)表單,可以保存,恢復(fù),驗(yàn)證值.看似不復(fù)雜,但是主要問(wèn)題在于表單中元素的內(nèi)容和數(shù)目完全未知,而且因用戶而異.緊密耦合到 Name 和 Address 特定表單域的 validate 函數(shù)不會(huì)起作用,因?yàn)闊o(wú)法驗(yàn)證哪些域...
現(xiàn)在是組合模式大展身手的時(shí)候,首先,我們要逐個(gè)驗(yàn)證表單的各個(gè)組成元素,判斷屬于組合對(duì)象還是葉對(duì)象.表單最基本的構(gòu)成要素是用戶用于輸入數(shù)據(jù)的域,由input, select,textarea 等等組成.上面一層是用于組織域的 fieldset 標(biāo)簽.最頂層是表單自身.
葉對(duì)象 (input) --| | -- 組合對(duì)象 (filedset) | 葉對(duì)象 (input) --| | |=組合對(duì)象 (form) 葉對(duì)象 (select) --| | --組合對(duì)象 (fieldset) | 葉對(duì)象 (textarea)--| |
組合對(duì)象和其所有子對(duì)象都具有相同的接口,可能有人會(huì)把他們看成超類(lèi)和子類(lèi)的關(guān)系,但是并非如此,葉對(duì)象沒(méi)有繼承上一級(jí)組合對(duì)象.
首先是創(chuàng)建一個(gè)動(dòng)態(tài)表單并且實(shí)現(xiàn)save 和 validate 操作.表單中實(shí)際擁有的域因用戶而異,所以 save,validate 函數(shù)不可能滿足每個(gè)人需要,不過(guò)可以設(shè)計(jì)一個(gè)模塊化表單,以便將來(lái)任何時(shí)候都能為其添加各種元素,不用修改 save 和 validate 函數(shù).
不用為表單元素的每一種可能組合編寫(xiě)一套方法,應(yīng)該讓這兩個(gè)方法和表單域自身關(guān)聯(lián)起來(lái).讓每個(gè)域都可以保存和驗(yàn)證自己:
nameFieldset.validate(); nameFieldset.save();
難點(diǎn)在于如何同時(shí)在所有域上執(zhí)行這些操作,使用組合模式來(lái)簡(jiǎn)化代碼:要保存所有域,只需一次調(diào)用:topForm.save();topForm 對(duì)象將會(huì)在所有子對(duì)象上遞歸調(diào)用 save 方法,實(shí)際的 save 操作只會(huì)發(fā)生在底層的葉對(duì)象上.組合對(duì)象志氣到了一個(gè)傳遞調(diào)用的作用.
實(shí)現(xiàn)代碼:
首先,創(chuàng)建組合對(duì)象和葉對(duì)象需要實(shí)現(xiàn)的兩個(gè)接口:
var Composite = new Interface("Composite", ["add", "remove", "getChild"]); var FormItem = new Interface("FormItem", ["save"]);
目前 FormItem 只要求實(shí)現(xiàn)一個(gè) save 函數(shù),稍后會(huì)對(duì)其進(jìn)行擴(kuò)充.
CompositeForm 類(lèi)的代碼如下:
var CompositeForm = function(id, method, action) { // implements Composite, Formitem this.formComponents = []; this.element = document.createElement("form"); this.element.id = id; this.element.method = method || "POST"; this.element.action = action || "#"; }; CompositeForm.prototype.add = function (child) { Interface.ensureImplements(child, Composite, FormItem); this.formComponents.push(child); this.element.appendChild(child.getElement()); }; CompositeForm.prototype.remove = function (child) { for (var i = 0, len = this.formComponents.length; i < len; i++) { if (this.formComponents[i] === child) { this.formComponents.splice(i, 1); // Remove one element from the array at position i. break; } } }; CompositeForm.prototype.getChild = function (i) { return this.formComponents[i]; }; CompositeForm.prototype.remove = function (child) { for (var i = 0, len = this.formComponents.length; i < len; i++) { this.formComponents[i].save(); } }; CompositeForm.prototype.getElement = function () { return this.element; };
CompositeForm 的子對(duì)象保存在一個(gè)數(shù)組中.使用 Interface.ensureImplements 是為了保證要添加到組合對(duì)象中的對(duì)象實(shí)現(xiàn)了正確的接口.
現(xiàn)在看看葉對(duì)象類(lèi):
var Field = function (id) { // implements Composite, FormItem this.id = id; }; Field.prototype.add = function () {}; Field.prototype.remove = function () {}; Field.prototype.getChild = function () {}; Field.prototype.save = function () { setCookie(this.id, this.getValue()); }; Field.prototype.getElement = function () { return this.element; }; Field.prototype.getValue = function () { throw new Error("Unsupported operation on the class Field."); };
這個(gè)類(lèi)將被各個(gè)葉對(duì)象類(lèi)繼承.它將 Composite 接口中的方法實(shí)現(xiàn)為空函數(shù),因?yàn)槿~節(jié)點(diǎn)不會(huì)有子對(duì)象.
這里最簡(jiǎn)單地實(shí)現(xiàn)了 save 方法.但是把用戶原始數(shù)據(jù)放在 Cookie 是一個(gè)非常糟糕的做法.因?yàn)?Cookie 很容易被篡改,所以數(shù)據(jù)的有效性得不到保證.其次,存儲(chǔ)在 Cookie 中的數(shù)據(jù)有大小限制.所以用戶的數(shù)據(jù)可能不會(huì)被全部保存下來(lái). 最后,還會(huì)影響性能,因?yàn)槊看握?qǐng)求中 Cookie 都會(huì)作為 http 頭被一起發(fā)送.
save 方法用 getValue 方法獲得所要保存的對(duì)象值,getValue() 方法各個(gè)子類(lèi)中的實(shí)現(xiàn)各不相同.使用 save 方法,不用提交表單也能保存表單的內(nèi)容.
這個(gè)對(duì)于長(zhǎng)表單來(lái)說(shuō)很有用,因?yàn)橛脩艨梢圆挥锰钔瓯韱沃型颈4? 然后忙完其他事情再來(lái)完成表單的填寫(xiě):
var InputField = function(id, label) { // implements Composite, FormItem Field.call(this, id); this.input = document.createElement("input"); this.input.id = id; this.label = document.createElement("label"); var labelTextNode = document.createTextNode(label); this.label.appendChild(lavelTExtNode); this.element = document.createElement("div"); this.element.className = "input-field"; this.label.appendChild(this.label); this.label.appendChild(this.input); }; extend(InputField, Field); // Inherit from Field. InputField.prototype.getValue = function () { return this.input.value; };
InputField 是 Field 的子類(lèi)之一.大多數(shù)方法都是從Field 繼承而來(lái).但是他也實(shí)現(xiàn)了針對(duì) input 標(biāo)簽的 getValue 方法的代碼.TextareaField 和 SelectField 也實(shí)現(xiàn)了自己特有的 getValue 方法.
var TextareaField = function(id, label) { // implements Composite, FormItem Field.call(this, id); this.textarea = document.createElement("textarea"); this.textarea.id = id; this.label = document.createElement("label"); var labelTextNode = document.createElement("select"); this.select.id = id; this.element = document.createElement("div"); this.element.className = "input-field"; this.element.appendChild(this.label); this.element.appendChild(this.select); }; extend(SelectField, Field); // Inherit from Field. SelectField.prototype.getValue = function () { return this.select.options[this.select.selectedIndex].value; };利
使用組合模式,簡(jiǎn)單的操作也能產(chǎn)生復(fù)雜的結(jié)果.不必編寫(xiě)大量手工遍歷數(shù)據(jù)或者其他數(shù)據(jù)結(jié)構(gòu)的粘合代碼,只需對(duì)最頂層的對(duì)象執(zhí)行操作,讓每一個(gè)子對(duì)象自己傳遞這個(gè)操作.
組合模式中,各個(gè)對(duì)象之間的耦合非常松散.只要他們實(shí)現(xiàn)了同樣的接口,那么改變他們的位置或者互相交換很簡(jiǎn)單.促進(jìn)了代碼得寵用,也有利于代碼重構(gòu).
用組合模式組織起來(lái)的對(duì)象形成了一個(gè)出色的層次體系.每當(dāng)對(duì)頂層對(duì)象執(zhí)行一個(gè)操作時(shí),實(shí)際上是在對(duì)整個(gè)結(jié)構(gòu)進(jìn)行深度優(yōu)先搜索以查找節(jié)點(diǎn).在該層次體系中添加,刪除,查找節(jié)點(diǎn)都很容易.
組合對(duì)象的易用性可能掩蓋了它所支持的每一種操作的代價(jià).由于對(duì)組合對(duì)象調(diào)用的任何操作都會(huì)被傳遞到他的所有子對(duì)象,那么如果層次體系很大,系統(tǒng)的性能就會(huì)受到影響.topGallery.show()這樣一個(gè)方法的調(diào)用會(huì)引起一次對(duì)整個(gè)數(shù)結(jié)構(gòu)的遍歷.
小結(jié)它將一批子對(duì)象組織為樹(shù)形結(jié)構(gòu),只要一條命令就可以操作樹(shù)中的所有對(duì)象.他提高了代碼的模塊化程度,而且便于代碼重構(gòu)和對(duì)象的替換.這種模式特別適用于動(dòng)態(tài)的 HTML 用戶界面,在他的幫助下,可以在不知道用戶界面的最終格局的情況下進(jìn)行開(kāi)發(fā).
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80460.html
摘要:橋接模式和裝飾模式的區(qū)別設(shè)計(jì)模式裝飾模式橋接模式和裝飾模式都是通過(guò)將繼承關(guān)系轉(zhuǎn)換為關(guān)聯(lián)關(guān)系從而減少系統(tǒng)中類(lèi)的數(shù)量,降低系統(tǒng)的耦合性。裝飾器模式支持多層裝飾,通過(guò)不同的組合可以實(shí)現(xiàn)不同的行為。 產(chǎn)生橋接模式的動(dòng)機(jī): 假設(shè)這樣一種情況:我們有大中小型號(hào)的毛筆,有紅藍(lán)黑三種顏料。如果需要不同顏色,不同型號(hào)的毛筆有如下兩種設(shè)計(jì)方法: 為每一種型號(hào)的毛筆都提供三種顏料的版本。 將毛筆和顏料分開(kāi)...
摘要:門(mén)面模式燜面有兩個(gè)作用一是簡(jiǎn)化類(lèi)的接口二是消除類(lèi)與使用他的業(yè)務(wù)代碼之間的耦合他幾乎是所有庫(kù)的核心原則通過(guò)建立一些便利方法可以讓復(fù)雜系統(tǒng)變得更加簡(jiǎn)單易用燜面模式可以使庫(kù)提供的工具更加容易理解燜面可以簡(jiǎn)化錯(cuò)誤記錄或者跟蹤頁(yè)面視圖統(tǒng)計(jì)數(shù)據(jù)這類(lèi)這類(lèi) 門(mén)面模式 燜面,有兩個(gè)作用,一是簡(jiǎn)化類(lèi)的接口;二是消除類(lèi)與使用他的業(yè)務(wù)代碼之間的耦合.他幾乎是所有 JS 庫(kù)的核心原則.通過(guò)建立一些便利方法可以讓...
摘要:橋接模式中的所謂脫耦,就是指在一個(gè)軟件系統(tǒng)的抽象化和實(shí)現(xiàn)化之間使用關(guān)聯(lián)關(guān)系組合或者聚合關(guān)系而不是繼承關(guān)系,從而使兩者可以相對(duì)獨(dú)立地變化,這就是橋接模式的用意。 0x01.定義與類(lèi)型 定義:將抽象部分與它的具體實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。 橋接模式將繼承關(guān)系轉(zhuǎn)化成關(guān)聯(lián)關(guān)系,它降低了類(lèi)與類(lèi)之間的耦合度,減少了系統(tǒng)中類(lèi)的數(shù)量,也減少了代碼量。 橋接模式中的所謂脫耦,就是指在一個(gè)軟...
摘要:橋接模式概述橋接模式將抽象部分與它的實(shí)現(xiàn)部分分離,使他們都可以獨(dú)立地變化。實(shí)現(xiàn)使用發(fā)送信息的例子來(lái)實(shí)現(xiàn)橋接模式。橋接模式也從側(cè)面體現(xiàn)了使用對(duì)象組合的方式比繼承要來(lái)得更靈活。代碼實(shí)現(xiàn)橋接模式 橋接模式 概述 橋接模式將抽象部分與它的實(shí)現(xiàn)部分分離,使他們都可以獨(dú)立地變化。通俗地說(shuō),橋接就是在不同的東西之間搭一個(gè)橋,讓它們能夠連接起來(lái),可以相互通訊和使用。在橋接模式中的橋接是在被分離的抽象部...
摘要:橋接模式橋接是用于把抽象化與現(xiàn)實(shí)化解耦,使得二者可以獨(dú)立變化,這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它通過(guò)提供抽象化和現(xiàn)實(shí)化之間的橋接結(jié)構(gòu),實(shí)現(xiàn)二者的解耦。所以接口和實(shí)現(xiàn)是可以組合的,這種組合我們稱之為橋接模式。主要用在系統(tǒng)開(kāi)始設(shè)計(jì)的時(shí)候使用。 橋接模式 橋接(Bridge)是用于把抽象化與現(xiàn)實(shí)化解耦,使得二者可以獨(dú)立變化,這種類(lèi)型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它通過(guò)提供抽象化和現(xiàn)實(shí)化之間的橋...
閱讀 2323·2021-11-08 13:13
閱讀 1255·2021-10-09 09:41
閱讀 1700·2021-09-02 15:40
閱讀 3195·2021-08-17 10:13
閱讀 2558·2019-08-29 16:33
閱讀 3134·2019-08-29 13:17
閱讀 3143·2019-08-29 11:00
閱讀 3305·2019-08-26 13:40