欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
javascript 設計模式

javascript 設計模式 - 文章很長(cháng),請自備瓜子,水果和眼藥水

2011-08-31 23:55 by 聶微東, 11780 visits, 收藏, 編輯

  一直都在考慮這個(gè)月分享大家什么東西最好,原計劃是打算寫(xiě)一些HTML5中JS方面的內容或者是AJAX方面的,可是自己由于表達能力,時(shí)間,還有個(gè)人工作方面的問(wèn)題,這個(gè)還是等下個(gè)月再做分享吧^.^。

  老規矩,開(kāi)始正文以前先交代自己寫(xiě)這篇文章的目的和一些注意事項:

  1.首先本人一直從事前端開(kāi)發(fā),所以除了JavaScript其他的語(yǔ)言了解不深,所以文章只會(huì )以JavaScript語(yǔ)言的角度去論證;

  2.其實(shí)我個(gè)人在項目用過(guò)的模式也不多,對模式的概念的理解也沒(méi)有那么抽象,所以最近在面試中如果面試官問(wèn)到與模式相關(guān)的問(wèn)題,自己感覺(jué)在對答過(guò)程中很郁悶,很多東西表達不清楚,于是就找了些相關(guān)資料,才會(huì )有這篇文章分享;

  3.JavaScript模式與前端的工作和成長(cháng)密不可分,因為這確實(shí)不是一個(gè)簡(jiǎn)單的話(huà)題,所以我只能盡力用簡(jiǎn)單表達和例子闡明,而且園子里有很多的高手,所以希望大家踴躍發(fā)言(由于水平有限,請大家多多指教,希望嘴下留情);

  4.由于這篇文章更多的只是想起到一個(gè)介紹和講解的作用,并不打算對每種模式進(jìn)行細致的分析,所以每種模式只用到一個(gè)至二個(gè)例子,可能會(huì )造成這個(gè)例子的表達并不是最優(yōu)的或者不夠全面,如果各位看官覺(jué)得不過(guò)癮,可以再去查找相關(guān)資料;

  5.做任何事都需要堅持,寫(xiě)博客也是一樣,嘿嘿,每月至少一篇(文章確實(shí)較長(cháng),希望能對朋友們有所幫助,重點(diǎn)部分在前言中有介紹,大家可以選擇感興趣的模式進(jìn)行深入)。

  6.歡迎轉載,不過(guò)請注明出處,謝謝。
 

了解JavaScript設計模式我們需要知道的一些必要知識點(diǎn):(內容相對基礎,高手請跳過(guò))

  閉包:關(guān)于閉包這個(gè)月在園子里有幾篇不錯的分享了,在這我也從最實(shí)際的地方出發(fā),說(shuō)說(shuō)我的理解。

    1.閉包最常用的方式就是返回一個(gè)內聯(lián)函數(何為內聯(lián)函數?就是在函數內部聲明的函數);

    2.在JavaScript中有作用域和執行環(huán)境的問(wèn)題,在函數內部的變量在函數外部是無(wú)法訪(fǎng)問(wèn)的,在函數內部卻可以得到全局變量。由于種種原因,我們有時(shí)候需要得到函數內部的變量,可是用常規方法是得不到的,這時(shí)我們就可以創(chuàng )建一個(gè)閉包,用來(lái)在外部訪(fǎng)問(wèn)這個(gè)變量。

    3.閉包的用途 主要就是上一點(diǎn)提到的讀取函數內部變量,還有一個(gè)作用就是可以使這些變量一直保存在內存中。

    4.使用閉包要注意,由于變量被保存在內存中,所以會(huì )對內存造成消耗,所以不能濫用閉包。解決方法是 在退出函數之前,將不使用的局部變量全部刪除。

    最后還是上一套閉包的代碼吧,這樣更直觀(guān)。

 1   function f(){
2   var n = 999;
3   function f1(){
4    alert(n+=1);
5    }
6    return f1;
7   }
8   var result = f();
9   result(); // 1000
10   result(); // 1001
11   result(); // 1002


  封裝:通過(guò)將一個(gè)方法或者屬性聲明為私用的,可以讓對象的實(shí)現細節對其他對象保密以降低對象之間的耦合程度,可以保持數據的完整性并對其修改方式加以約束,這樣可以是代碼更可靠,更易于調試。封裝是面向對象的設計的基石。

  盡管JavaScript是一門(mén)面向對象的語(yǔ)言,可它并不具備將成員聲明為公用或私用的任何內部機制,所以我們只能自己想辦法實(shí)現這種特性。下面還是通過(guò)一套完整的代碼去分析,介紹什么是私有屬性和方法,什么是特權屬性和方法,什么是屬性和方法,什么是靜態(tài)屬性和方法。

  私有屬性和方法:函數有作用域,在函數內用var 關(guān)鍵字聲明的變量在外部無(wú)法訪(fǎng)問(wèn),私有屬性和方法本質(zhì)就是你希望在對象外部無(wú)法訪(fǎng)問(wèn)的變量。

  特權屬性和方法:創(chuàng )建屬性和方法時(shí)使用的this關(guān)鍵字,因為這些方法定義在構造器的作用域中,所以它們可以訪(fǎng)問(wèn)到私有屬性和方法;只有那些需要直接訪(fǎng)問(wèn)私有成員的方法才應該被設計為特權方法。

  共有屬性和方法:直接鏈在prototype上的屬性和方法,不可以訪(fǎng)問(wèn)構造器內的私有成員,可以訪(fǎng)問(wèn)特權成員,子類(lèi)會(huì )繼承所有的共有方法。

  共有靜態(tài)屬性和方法:最好的理解方式就是把它想象成一個(gè)命名空間,實(shí)際上相當于把構造器作為命名空間來(lái)使用。

 

 1   /* -- 封裝 -- */
2   var _packaging =function(){
3   //私有屬性和方法
4   var name ='Darren';
5   var method1 =function(){
6    //...
7   }
8   //特權屬性和方法
9   this.title ='JavaScript Design Patterns' ;
10   this.getName =function(){
11    return name;
12   }
13   }
14   //共有靜態(tài)屬性和方法
15   _packaging._name ='Darren code';
16   _packaging.alertName =function(){
17   alert(_packaging._name);
18   }
19   //共有屬性和方法
20   _packaging.prototype = {
21   init:function(){
22   //...
23   }
24   }


  繼承:繼承本身就是一個(gè)抽象的話(huà)題,在JavaScript中繼承更是一個(gè)復雜的話(huà)題,因為JavaScript想要實(shí)現繼承有兩種實(shí)現方式,分別是類(lèi)式繼承和原型式繼承,每種實(shí)現的方式都需要采取不少措施,下面本人通過(guò)分析例子的方式講解JavaScript中這個(gè)很重要的話(huà)題。

 1   /* -- 類(lèi)式繼承 -- */
2   //先聲明一個(gè)超類(lèi)
3   function Person(name){
4     this.name = name;
5   }
6   //給這個(gè)超類(lèi)的原型對象上添加方法 getName
7   Person.prototype.getName =function(){
8   returnthis.name;
9   }
10   //實(shí)例化這個(gè)超類(lèi)
11   var a =new Person('Darren1')
12   alert(a.getName());
13   //再聲明類(lèi)
14   function Programmer(name,sex){
15   //這個(gè)類(lèi)中要調用超類(lèi)Person的構造函數,并將參數name傳給它
16   Person.call(this,name);
17   this.sex = sex;
18   }
19   //這個(gè)子類(lèi)的原型對象等于超類(lèi)的實(shí)例
20   Programmer.prototype =new Person();
21   //因為子類(lèi)的原型對象等于超類(lèi)的實(shí)例,所以prototype.constructor這個(gè)方法也等于超類(lèi)構造函數,你可以自己測試一下,如果沒(méi)這一步,alert(Programmer.prototype.constructor),這個(gè)是Person超類(lèi)的引用,所以要從新賦值為自己本身
22   Programmer.prototype.constructor = Programmer;
23   //子類(lèi)本身添加了getSex 方法
24   Programmer.prototype.getSex =function(){
25   returnthis.sex;
26   }
27   //實(shí)例化這個(gè)子類(lèi)
28   var _m =new Programmer('Darren2','male');
29   //自身的方法
30   alert(_m.getSex());
31   //繼承超類(lèi)的方法
32   alert(_m.getName());

  代碼都不難,只要對 原型鏈 有基礎就能理解。類(lèi)式繼承模式是JavaScript繼承主要的模式,幾乎所有用面向對象方式編寫(xiě)的JavaScript代碼中都用到了這種繼承,又因為在各種流行語(yǔ)言中只有JavaScript使用原型式繼承,因此最好還是使用類(lèi)式繼承??墒且煜avaScript語(yǔ)言,原型繼承也是我們必須所了解的,至于在項目中是否使用就得看個(gè)人編碼風(fēng)格了。

 1   /* -- 原型式繼承 -- */
2   //clone()函數用來(lái)創(chuàng )建新的類(lèi)Person對象
3   var clone =function(obj){
4 var _f =function(){};
5   //這句是原型式繼承最核心的地方,函數的原型對象為對象字面量
6   _f.prototype = obj;
7   returnnew _f;
8   }
9   //先聲明一個(gè)對象字面量
10   var Person = {
11   name:'Darren',
12   getName:function(){
13   returnthis.name;
14   }
15   }
16   //不需要定義一個(gè)Person的子類(lèi),只要執行一次克隆即可
17   var Programmer = clone(Person);
18   //可以直接獲得Person提供的默認值,也可以添加或者修改屬性和方法
19   alert(Programmer.getName())
20   Programmer.name ='Darren2'
21   alert(Programmer.getName())
22
23   //聲明子類(lèi),執行一次克隆即可
24   var Someone = clone(Programmer);


  ------------------------------------------  正文開(kāi)始了,我是分割線(xiàn)  ------------------------------------------
 
  前言:

  JavaScript設計模式的作用 - 提高代碼的重用性,可讀性,使代碼更容易的維護和擴展。

   

  1.單體模式,工廠(chǎng)模式,橋梁模式個(gè)人認為這個(gè)一個(gè)優(yōu)秀前端必須掌握的模式,對抽象編程和接口編程都非常有好處。

  2.裝飾者模式和組合模式有很多相似的地方,它們都與所包裝的對象實(shí)現同樣的接口并且會(huì )把任何方法的調用傳遞給這些對象。裝飾者模式和組合模式是本人描述的較吃力的兩個(gè)模式,我個(gè)人其實(shí)也沒(méi)用過(guò),所以查了很多相關(guān)資料和文檔,請大家海涵。

  3.門(mén)面模式是個(gè)非常有意思的模式,幾乎所有的JavaScript庫都會(huì )用到這個(gè)模式,假如你有逆向思維或者逆向編程的經(jīng)驗,你會(huì )更容易理解這個(gè)模式(聽(tīng)起來(lái)有挑戰,其實(shí)一接觸你就知道這是個(gè)很簡(jiǎn)單的模式);還有配置器模式得和門(mén)面模式一塊拿來(lái)說(shuō),這個(gè)模式對現有接口進(jìn)行包裝,合理運用可以很多程度上提高開(kāi)發(fā)效率。這兩個(gè)模式有相似的地方,所以一塊理解的話(huà)相信都會(huì )很快上手的。

  4.享元模式是一種以?xún)?yōu)化為目的的模式。

  5.代理模式主要用于控制對象的訪(fǎng)問(wèn),包括推遲對其創(chuàng )建需要耗用大量計算資源的類(lèi)得實(shí)例化。

  6.觀(guān)察者模式用于對對象的狀態(tài)進(jìn)行觀(guān)察,并且當它發(fā)生變化時(shí)能得到通知的方法。用于讓對象對事件進(jìn)行監聽(tīng)以便對其作出響應。觀(guān)察者模式也被稱(chēng)為“訂閱者模式”。

  7.命令模式是對方法調用進(jìn)行封裝的方式,用命名模式可以對方法調用進(jìn)行參數化和傳遞,然后在需要的時(shí)候再加以執行。

  8.職責鏈模式用來(lái)消除請求的發(fā)送者和接收者之間的耦合。
 
 

  JavaScript設計模式都有哪些?

  單體(Singleton)模式: 絕對是JavaScript中最基本最有用的模式。

  單體在JavaScript的有多種用途,它用來(lái)劃分命名空間??梢詼p少網(wǎng)頁(yè)中全局變量的數量(在網(wǎng)頁(yè)中使用全局變量有風(fēng)險);可以在多人開(kāi)發(fā)時(shí)避免代碼的沖突(使用合理的命名空間)等等。

  在中小型項目或者功能中,單體可以用作命名空間把自己的代碼組織在一個(gè)全局變量名下;在稍大或者復雜的功能中,單體可以用來(lái)把相關(guān)代碼組織在一起以便日后好維護?! ?/p>

  使用單體的方法就是用一個(gè)命名空間包含自己的所有代碼的全局對象,示例:

1   var functionGroup = {
2     name:'Darren',
3     method1:function(){
4       //code
5     },
6     init:function(){
7       //code
8     }
9   }

  或者

1   var functionGroup  =newfunction myGroup(){
2     this.name ='Darren';
3     this.getName =function(){
4       returnthis.name
5     }
6     this.method1 =function(){}
7     ...
8   }

   

  工廠(chǎng)(Factory)模式:提供一個(gè)創(chuàng )建一系列相關(guān)或相互依賴(lài)對象的接口,而無(wú)需指定他們具體的類(lèi)。

  工廠(chǎng)就是把成員對象的創(chuàng )建工作轉交給一個(gè)外部對象,好處在于消除對象之間的耦合(何為耦合?就是相互影響)。通過(guò)使用工廠(chǎng)方法而不是new關(guān)鍵字及具體類(lèi),可以把所有實(shí)例化的代碼都集中在一個(gè)位置,有助于創(chuàng )建模塊化的代碼,這才是工廠(chǎng)模式的目的和優(yōu)勢。

  舉個(gè)例子:你有一個(gè)大的功能要做,其中有一部分是要考慮擴展性的,那么這部分代碼就可以考慮抽象出來(lái),當做一個(gè)全新的對象做處理。好處就是將來(lái)擴展的時(shí)候容易維護 - 只需要操作這個(gè)對象內部方法和屬性,達到了動(dòng)態(tài)實(shí)現的目的。非常有名的一個(gè)示例 - XHR工廠(chǎng)

 1   var XMLHttpFactory =function(){};      //這是一個(gè)簡(jiǎn)單工廠(chǎng)模式
2   XMLHttpFactory.createXMLHttp =function(){
3     var XMLHttp = null;
4     if (window.XMLHttpRequest){
5       XMLHttp = new XMLHttpRequest()
6     }elseif (window.ActiveXObject){
7       XMLHttp = new ActiveXObject("Microsoft.XMLHTTP")
8     }
10   return XMLHttp;
11   }
12   //XMLHttpFactory.createXMLHttp()這個(gè)方法根據當前環(huán)境的具體情況返回一個(gè)XHR對象。
13   var AjaxHander =function(){
14     var XMLHttp = XMLHttpFactory.createXMLHttp();
15     ...
16   }


  工廠(chǎng)模式又區分簡(jiǎn)單工廠(chǎng)模式和抽象工廠(chǎng)模式,上面介紹的是簡(jiǎn)單工廠(chǎng)模式,這種模式用的更多也更簡(jiǎn)單易用。抽象工廠(chǎng)模式的使用方法就是 - 先設計一個(gè)抽象類(lèi),這個(gè)類(lèi)不能被實(shí)例化,只能用來(lái)派生子類(lèi),最后通過(guò)對子類(lèi)的擴展實(shí)現工廠(chǎng)方法。 示例:

 1   var XMLHttpFactory =function(){};      //這是一個(gè)抽象工廠(chǎng)模式
2   XMLHttpFactory.prototype = {
3   //如果真的要調用這個(gè)方法會(huì )拋出一個(gè)錯誤,它不能被實(shí)例化,只能用來(lái)派生子類(lèi)
4   createFactory:function(){
5   thrownew Error('This is an abstract class');
6   }
7   }
8   //派生子類(lèi),文章開(kāi)始處有基礎介紹那有講解繼承的模式,不明白可以去參考原理
9   var XHRHandler =function(){
10   XMLHttpFactory.call(this);
11   };
12   XHRHandler.prototype =new XMLHttpFactory();
13   XHRHandler.prototype.constructor = XHRHandler;
14   //重新定義createFactory 方法
15   XHRHandler.prototype.createFactory =function(){
16   var XMLHttp =null;
17   if (window.XMLHttpRequest){
18   XMLHttp =new XMLHttpRequest()
19   }elseif (window.ActiveXObject){
20   XMLHttp =new ActiveXObject("Microsoft.XMLHTTP")
21   }
22   return XMLHttp;
23   }

  

  橋接(bridge)模式:在實(shí)現API的時(shí)候,橋梁模式灰常有用。在所有模式中,這種模式最容易立即付諸實(shí)施。

  橋梁模式可以用來(lái)弱化它與使用它的類(lèi)和對象之間的耦合,就是將抽象與其實(shí)現隔離開(kāi)來(lái),以便二者獨立變化;這種模式對于JavaScript中常見(jiàn)的時(shí)間驅動(dòng)的編程有很大益處,橋梁模式最常見(jiàn)和實(shí)際的應用場(chǎng)合之一是時(shí)間監聽(tīng)器回調函數。先分析一個(gè)不好的示例:

 

1   element.onclick =function(){
2   new setLogFunc();
3   };

 

  為什么說(shuō)這個(gè)示例不好,因為從這段代碼中無(wú)法看出那個(gè)LogFunc方法要顯示在什么地方,它有什么可配置的選項以及應該怎么去修改它。換一種說(shuō)法就是,橋梁模式的要訣就是讓接口“可橋梁”,實(shí)際上也就是可配置。把頁(yè)面中一個(gè)個(gè)功能都想象成模塊,接口可以使得模塊之間的耦合降低。

  掌握橋梁模式的正確使用收益的不只是你,還有那些負責維護你代碼的人。把抽象于其實(shí)現隔離開(kāi),可獨立地管理軟件的各個(gè)部分,bug也因此更容易查找。

  橋梁模式目的就是讓API更加健壯,提高組件的模塊化程度,促成更簡(jiǎn)潔的實(shí)現,并提高抽象的靈活性。一個(gè)好的示例:

1   element.onclick =function(){  //API可控制性提高了,使得這個(gè)API更加健壯
2   new someFunction(element,param,callback);
3   }

  注:橋梁模式還可以用于連接公開(kāi)的API代碼和私有的實(shí)現代碼,還可以把多個(gè)類(lèi)連接在一起。在文章封裝介紹的部分提到過(guò)特權方法,也是橋梁模式的一種特例?!禞S設計模式》上找的示例,加深大家對這個(gè)模式的理解:

 1   //錯誤的方式
2   //這個(gè)API根據事件監聽(tīng)器回調函數的工作機制,事件對象被作為參數傳遞給這個(gè)函數。本例中并沒(méi)有使用這個(gè)參數,而只是從this對象獲取ID。
3   addEvent(element,'click',getBeerById);
4   function(e){
5   var id =this.id;
6   asyncRequest('GET','beer.url?id='+ id,function(resp){
7   //Callback response
8    console.log('Requested Beer: '+ resp.responseText);
9   });
10   }
11
12   //好的方式
13   //從邏輯上分析,把id傳給getBeerById函數式合情理的,且回應結果總是通過(guò)一個(gè)毀掉函數返回。這么理解,我們現在做的是針對接口而不是實(shí)現進(jìn)行編程,用橋梁模式把抽象隔離開(kāi)來(lái)。
14   function getBeerById(id,callback){
15   asyncRequest('GET','beer.url?id='+ id,function(resp){
16   callback(resp.responseText)
17   });
18   }
19   addEvent(element,'click',getBeerByIdBridge);
20   function getBeerByIdBridge(e){
21   getBeerById(this.id,function(beer){
22   console.log('Requested Beer: '+ beer);
23   });
24   } 


  裝飾者(Decorator)模式:這個(gè)模式就是為對象增加功能(或方法)。

  動(dòng)態(tài)地給一個(gè)對象添加一些額外的職責。就擴展功能而言,它比生成子類(lèi)方式更為靈活。

  裝飾者模式和組合模式有很多共同點(diǎn),它們都與所包裝的對象實(shí)現統一的接口并且會(huì )把任何方法條用傳遞給這些對象??墒墙M合模式用于把眾多子對象組織為一個(gè)整體,而裝飾者模式用于在不修改現有對象或從派生子類(lèi)的前提下為其添加方法。

  裝飾者的運作過(guò)程是透明的,這就是說(shuō)你可以用它包裝其他對象,然后繼續按之前使用那么對象的方法來(lái)使用,從下面的例子中就可以看出。還是從代碼中理解吧:

 1   //創(chuàng  )建一個(gè)命名空間為myText.Decorations
2   var myText= {};
3   myText.Decorations={};
4   myText.Core=function(myString){
5   this.show =function(){return myString;}
6   }
7   //第一次裝飾
8   myText.Decorations.addQuestuibMark =function(myString){
9   this.show =function(){return myString.show()+'?';};
10   }
11   //第二次裝飾
12   myText.Decorations.makeItalic =function(myString){
13   this.show =function(){return'<li>'+myString.show()+'</li>'};
14   }
15   //得到myText.Core的實(shí)例
16   var theString =new myText.Core('this is a sample test String');
17   alert(theString.show());  //output 'this is a sample test String'
18   theString =new myText.Decorations.addQuestuibMark(theString);
19   alert(theString.show());  //output 'this is a sample test String?'
20   theString =new myText.Decorations.makeItalic (theString);
21   alert(theString.show());  //output '<li>this is a sample test String</li>'

 

  從這個(gè)示例中可以看出,這一切都可以不用事先知道組件對象的接口,甚至可以動(dòng)態(tài)的實(shí)現,在為現有對象增添特性這方面,裝飾者模式有極大的靈活性。

  如果需要為類(lèi)增加特性或者方法,而從該類(lèi)派生子類(lèi)的解決辦法并不實(shí)際的話(huà),就應該使用裝飾者模式。派生子類(lèi)之所以會(huì )不實(shí)際最常見(jiàn)的原因是需要添加的特性或方法的數量要求使用大量子類(lèi)。

 

 

  組合(Composite)模式:將對象組合成樹(shù)形結構以表示“部分-整體”的層次結構。它使得客戶(hù)對單個(gè)對象和復合對象的使用具有一致性。

  組合模式是一種專(zhuān)為創(chuàng )建Web上的動(dòng)態(tài)用戶(hù)界面而量身定制的模式。使用這種模式,可以用一條命令在多個(gè)對象上激發(fā)復雜的或遞歸的行為。組合模式擅長(cháng)于對大批對象進(jìn)行操作。

  組合模式的好處:1.程序員可以用同樣的方法處理對象的集合與其中的特定子對象;2.它可以用來(lái)把一批子對象組織成樹(shù)形結構,并且使整棵樹(shù)都可被便利。

  組合模式適用范圍:1.存在一批組織成某處層次體系的對象(具體結構可能在開(kāi)發(fā)期間無(wú)法知道);2.希望對這批對象或其中的一部分對象實(shí)話(huà)一個(gè)操作。

  其實(shí)組合模式就是將一系列相似或相近的對象組合在一個(gè)大的對象,由這個(gè)大對象提供一些常用的接口來(lái)對這些小對象進(jìn)行操作,代碼可重用,對外操作簡(jiǎn)單。例如:對form內的元素,不考慮頁(yè)面設計的情況下,一般就剩下input了,對于這些input都有name和value的屬性,因此可以將這些input元素作為form對象的成員組合起來(lái),form對象提供對外的接口,便可以實(shí)現一些簡(jiǎn)單的操作,比如設置某個(gè)input的value,添加/刪除某個(gè)input等等。

  這種模式描述起來(lái)比較吃力,我從《JS設計模式》上找個(gè)一個(gè)實(shí)例,大家還是看代碼吧:先創(chuàng )建組合對象類(lèi)

 1   // DynamicGallery Class
2   var DynamicGallery =function (id) { // 實(shí)現Composite,GalleryItem組合對象類(lèi)
3   this.children = [];
4   this.element = document.createElement('div');
5   this.element.id = id;
6   this.element.className ='dynamic-gallery';
7   }
8   DynamicGallery.prototype = {
9   // 實(shí)現Composite組合對象接口
10   add: function (child) {
11   this.children.push(child);
12   this.element.appendChild(child.getElement());
13   },
14   remove: function (child) {
15   for (var node, i =0; node =this.getChild(i); i++) {
16   if (node == child) {
17   this.children.splice(i, 1);
18    break;
19   }
20   }
21   this.element.removeChild(child.getElement());
22   },
23   getChild: function (i) {
24   returnthis.children[i];
25   },
26   // 實(shí)現DynamicGallery組合對象接口
27   hide: function () {
28   for (var node, i =0; node =this.getChild(i); i++) {
29   node.hide();
30   }
31   this.element.style.display ='none';
32   },
33   show: function () {
34   this.element.style.display ='block';
35   for (var node, i =0; node = getChild(i); i++) {
36   node.show();
37   }
38   },
39   // 幫助方法
40   getElement: function () {
41   returnthis.element;
42   }
43   }

  再創(chuàng )建葉對象類(lèi)

 1   var GalleryImage =function (src) { // 實(shí)現Composite和GalleryItem組合對象中所定義的方法 
2   this.element = document.createElement('img');
3   this.element.className ='gallery-image';
4   this.element.src = src;
5   }
6   GalleryImage.prototype = {
7   // 實(shí)現Composite接口
8   // 這些是葉結點(diǎn),所以我們不用實(shí)現這些方法,我們只需要定義即可
9   add: function () { },
10   remove: function () { },
11   getChild: function () { },
12   // 實(shí)現GalleryItem接口
13   hide: function () {
14   this.element.style.display ='none';
15   },
16   show: function () {
17   this.element.style.display ='';
18   },
19   // 幫助方法
20   getElement: function () {
21   returnthis.element;
22   }
23   }

  現在我們可以使用這兩個(gè)類(lèi)來(lái)管理圖片:

 1   var topGallery =new DynamicGallery('top-gallery'); 
2   topGallery.add(new GalleryImage('/img/image-1.jpg'));
3   topGallery.add(new GalleryImage('/img/image-2.jpg'));
4   topGallery.add(new GalleryImage('/img/image-3.jpg'));
5   var vacationPhotos =new DyamicGallery('vacation-photos');
6   for(var i =0, i <30; i++){
7     vacationPhotos.add(new GalleryImage('/img/vac/image-'+ i +'.jpg'));
8   }
9   topGallery.add(vacationPhotos);
10   topGallery.show();
11   vacationPhotos.hide();

 

  門(mén)面(facade)模式:門(mén)面模式是幾乎所有JavaScript庫的核心原則
  子系統中的一組接口提供一個(gè)一致的界面,門(mén)面模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統更加容易使用,簡(jiǎn)單的說(shuō)這是一種組織性的模式,它可以用來(lái)修改類(lèi)和對象的接口,使其更便于使用。

  門(mén)面模式的兩個(gè)作用:1.簡(jiǎn)化類(lèi)的接口;2.消除類(lèi)與使用它的客戶(hù)代碼之間的耦合。

  門(mén)面模式的使用目的就是圖方面。

  想象一下計算機桌面上的那些快捷方式圖標,它們就是在扮演一個(gè)把用戶(hù)引導至某個(gè)地方的接口的角色,每次操作都是間接的執行一些幕后的命令。

  你在看這篇的博客的時(shí)候我就假設你已經(jīng)有JavaScript的使用經(jīng)驗了,那么你一定寫(xiě)過(guò)或者看過(guò)這樣的代碼:

1   var addEvent =function(el,type,fn){
2   if(window.addEventListener){
3   el.addEventListener(type,fn);
4   }elseif(window.attachEvent){
5   el.attachEvent('on'+type,fn);
6   }else{
7   el['on'+type] = fn;
8   }
9   }

 

  這個(gè)就是一個(gè)JavaScript中常見(jiàn)的事件監聽(tīng)器函數,這個(gè)函數就是一個(gè)基本的門(mén)面,有了它,就有了為DOM節點(diǎn)添加事件監聽(tīng)器的簡(jiǎn)便方法。

  現在要說(shuō)門(mén)面模式的精華部分了,為什么說(shuō)JavaScript庫幾乎都會(huì )用這種模式類(lèi)。假如現在要設計一個(gè)庫,那么最好把其中所有的工具元素放在一起,這樣更好用,訪(fǎng)問(wèn)起來(lái)更簡(jiǎn)便??创a:

 1   //_model.util是一個(gè)命名空間
2   _myModel.util.Event = {
3   getEvent:function(e){
4   return e|| window.event;
5   },
6   getTarget:function(e){
7   return e.target||e.srcElement;
8   },
9   preventDefault:function(e){
10   if(e.preventDefault){
11   e.preventDefault();
12   }else{
13   e.returnValue =false;
14   }
15   }
16   };
17   //事件工具大概就是這么一個(gè)套路,然后結合addEvent函數使用
18   addEvent(document.getElementsByTagName('body')[0],'click',function(e){
19   alert(_myModel.util.Event.getTarget(e));
20   });

  個(gè)人認為,在處理游覽器差異問(wèn)題時(shí)最好的解決辦法就是把這些差異抽取的門(mén)面方法中,這樣可以提供一個(gè)更一致的接口,addEvent函數就是一個(gè)例子。 


  適配置器(Adapter)模式:將一個(gè)類(lèi)的接口轉換成客戶(hù)希望的另外一個(gè)接口。適配器模式使得原本由于接口不兼容而不能一起工作的那些類(lèi)可以一起工作,使用這種模式的對象又叫包裝器,因為他們是在用一個(gè)新的接口包裝另一個(gè)對象。

  從表面上看,它和門(mén)面模式有點(diǎn)相似,差別在于它們如何改變接口,門(mén)面模式展現的是一個(gè)簡(jiǎn)化的接口,它并不提供額外的選擇,而適配器模式則要把一個(gè)接口轉換為另一個(gè)接口,它并不會(huì )濾除某些能力,也不會(huì )簡(jiǎn)化接口。先來(lái)一個(gè)簡(jiǎn)單的示例看看:

 1   //假如有一個(gè)3個(gè)字符串參數的函數,但是現在擁有的卻是一個(gè)包含三個(gè)字符串元素的對象,那么就可以用一個(gè)配置器來(lái)銜接二者
2   var clientObject = {
3   str1:'bat',
4   str2:'foo',
5   str3:'baz'
6   }
7   function interfaceMethod(str1,str2,str3){
8     alert(str1)
9   }
10   //配置器函數
11   function adapterMethod(o){
12   interfaceMethod(o.str1, o.str2, o.str3);
13   }
14   adapterMethod(clientObject)
15   //adapterMethod函數的作為就在于對interfaceMethod函數進(jìn)行包裝,并把傳遞給它的參數轉換為后者需要的形式。

  適配器模式的工作機制是:用一個(gè)新的接口對現有類(lèi)得接口進(jìn)行包裝。

  示例:適配兩個(gè)庫。下面的例子要實(shí)現的是從Prototype庫的$函數到YUI的get方法的轉換。

 1   //先看它們在接口方面的差別
2   //Prototype $ function
3   function $(){
4   var elements =new Array();
5   for(var i=0;i<arguments.length;i++){
6   var element = arguments[i];
7   if(typeof element =='string'){
8   element = document.getElementById(element);
9   }
10   if(typeof.length ==1) return element;
11   elements.push(element);
12   }
13   return elements;
14   }
15   //YUI get method
16   YAHOO.util.Dom.get =function(el){
17   if(YAHOO.lang.isString(el)){
18   return document.getElementById(el);
19   }
20   if(YAHOO.lang.isArray(el)){
21   var c =[];
22   for(var i=0,len=el.length;i<len;++i){
23   c[c.length] = YAHOO.util.Dom.get(el[i]);
24   }
25   return c;
26   }
27   if(el){
28   return el;
29   }
30   returnnull;
31   }
32   //二者區別就在于get具有一個(gè)參數,且可以是HTML,字符串或者數組;而$木有正是的參數,允許使用者傳入任意數目的參數,不管HTML還是字符串。
33   //如果需要從使用Prototype的$函數改為使用YUI的get方法(或者相反,那么用適配器模式其實(shí)很簡(jiǎn)單)
34   function PrototypeToYUIAdapter(){
35   return YAHOO.util.Dom.get(arguments);
36   }
37   function YUIToPrototypeAdapter(el){
38   return $.apply(window,el instanceof Array?el:[el]);
39   }

 

  享元(Flyweight)模式:運用共享技術(shù)有效地支持大量細粒度的對象。

  享元模式可以避免大量非常相似類(lèi)的開(kāi)銷(xiāo)。在程序設計中有時(shí)需要生成大量細粒度的類(lèi)實(shí)例來(lái)表示數據。如果發(fā)現這些實(shí)例除了幾個(gè)參數外基本傷都是相同的,有時(shí)就能夠受大幅度第減少需要實(shí)例化的類(lèi)的數量。如果能把這些參數移到類(lèi)實(shí)例外面,在方法調用時(shí)將他們傳遞進(jìn)來(lái),就可以通過(guò)共享大幅度地減少單個(gè)實(shí)例的數目。

  從實(shí)際出發(fā)說(shuō)說(shuō)自己的理解吧。

 1   組成部分
2   “享元”:抽離出來(lái)的外部操作和數據;
3   “工廠(chǎng)”:創(chuàng )造對象的工廠(chǎng);
4   “存儲器”:存儲實(shí)例對象的對象或數組,供“享元”來(lái)統一控制和管理。
5
6   應用場(chǎng)景
7   1. 頁(yè)面存在大量資源密集型對象;
8   2. 這些對象具備一定的共性,可以抽離出公用的操作和數據
9
10   關(guān)鍵
11   1. 合理劃分內部和外部數據。
12   既要保持每個(gè)對象的模塊性、保證享元的獨立、可維護,又要盡可能多的抽離外部數據。
13   2. 管理所有實(shí)例
14   既然抽離出了外部數據和操作,那享元就必須可以訪(fǎng)問(wèn)和控制實(shí)例對象。在JavaScript這種動(dòng)態(tài)語(yǔ)言中,這個(gè)需求是很容易實(shí)現的:我們可以把工廠(chǎng)生產(chǎn)出的對象簡(jiǎn)單的扔在一個(gè)數組中。為每個(gè)對象設計暴露給外部的方法,便于享元的控制。
15
16   優(yōu)點(diǎn)
17   1. 將能耗大的操作抽離成一個(gè),在資源密集型系統中,可大大減少資源和內存占用;
18   2. 職責封裝,這些操作獨立修改和維護;
19
20   缺點(diǎn)
21   1. 增加了實(shí)現復雜度。
22   將原本由一個(gè)工廠(chǎng)方法實(shí)現的功能,修改為了一個(gè)享元+一個(gè)工廠(chǎng)+一個(gè)存儲器。
23   2. 對象數量少的情況,可能會(huì )增大系統開(kāi)銷(xiāo)。

 

  示例:

 1   //汽車(chē)登記示例
2   var Car =function(make,model,year,owner,tag,renewDate){
3     this.make=make;
4     this.model=model;
5     this.year=year;
6     this.owner=owner;
7     this.tag=tag;
8     this.renewDate=renewDate;
9   }
10   Car.prototype = {
11     getMake:function(){
12       returnthis.make;
13     },
14     getModel:function(){
15       returnthis.model;
16     },
17     getYear:function(){
18       returnthis.year;
19     },
20     transferOwner:function(owner,tag,renewDate){
21       this.owner=owner;
22       this.tag=tag;
23       this.renewDate=renewDate;
24     },
25     renewRegistration:function(renewDate){
26       this.renewDate=renewDate;
27     }
28   }
29   //數據量小到?jīng)]多大的影響,數據量大的時(shí)候對計算機內存會(huì )產(chǎn)生壓力,下面介紹享元模式優(yōu)化后
30   //包含核心數據的Car類(lèi)
31   var Car=function(make,model,year){
32     this.make=make;
33     this.model=model;
34     this.year=year;
35   }
36   Car.prototype={
37     getMake:function(){
38       returnthis.make;
39     },
40     getModel:function(){
41       returnthis.model;
42     },
43     getYear:function(){
44       returnthis.year;
45     }
46   }
47   //中間對象,用來(lái)實(shí)例化Car類(lèi)
48   var CarFactory=(function(){
49     var createdCars = {};
50     return {
51       createCar:function(make,model,year){
52         var car=createdCars[make+"-"+model+"-"+year];
53         return car ? car : createdCars[make +'-'+ model +'-'+ year] =(new Car(make,model,year));
54       }
55     }
56   })();
57   //數據工廠(chǎng),用來(lái)處理Car的實(shí)例化和整合附加數據
58   var CarRecordManager = (function() {
59     var carRecordDatabase = {};
60     return {
61       addCarRecord:function(make,model,year,owner,tag,renewDate){
62         var car = CarFactory.createCar(make, model, year);
63         carRecordDatabase[tag]={
64           owner:owner,
65           tag:tag,
66           renewDate:renewDate,
67           car:car
68       }
69     },
70       transferOwnership:function(tag, newOwner, newTag, newRenewDate){
71         var record=carRecordDatabase[tag];
72         record.owner = newOwner;
73         record.tag = newTag;
74         record.renewDate = newRenewDate;
75       },
76       renewRegistration:function(tag,newRenewDate){
77         carRecordDatabase[tag].renewDate=newRenewDate;
78       },
79       getCarInfo:function(tag){
80         return carRecordDatabase[tag];
81       }
82     }
83   })();

  
  代理(Proxy)模式:
此模式最基本的形式是對訪(fǎng)問(wèn)進(jìn)行控制。代理對象和另一個(gè)對象(本體)實(shí)現的是同樣的接口,可是實(shí)際上工作還是本體在做,它才是負責執行所分派的任務(wù)的那個(gè)對象或類(lèi),代理對象不會(huì )在另以對象的基礎上修改任何方法,也不會(huì )簡(jiǎn)化那個(gè)對象的接口。

  舉一個(gè)具體的情況:如果那個(gè)對象在某個(gè)遠端服務(wù)器上,直接操作這個(gè)對象因為網(wǎng)絡(luò )速度原因可能比較慢,那我們可以先用Proxy來(lái)代替那個(gè)對象。
  總之對于開(kāi)銷(xiāo)較大的對象,只有在使用它時(shí)才創(chuàng )建,這個(gè)原則可以為我們節省很多內存?!禞S設計模式》上的圖書(shū)館示例:

 

 1   var Publication =new Interface('Publication', ['getIsbn', 'setIsbn', 'getTitle', 'setTitle', 'getAuthor', 'setAuthor', 'display']);
2   var Book =function(isbn, title, author) {
3    //...
4   }
5   // implements Publication
6   implements(Book,Publication);
7
8   /* Library interface. */
9   var Library =new Interface('Library', ['findBooks', 'checkoutBook', 'returnBook']);
10
11   /* PublicLibrary class. */
12   var PublicLibrary =function(books) {
13    //...
14   };
15   // implements Library
16   implements(PublicLibrary,Library);
17
18   PublicLibrary.prototype = {
19    findBooks: function(searchString) {
20    //...
21   },
22   checkoutBook: function(book) {
23    //...
24    },
25   returnBook: function(book) {
26    //...
27    }
28   };
29
30   /* PublicLibraryProxy class, a useless proxy. */
31   var PublicLibraryProxy =function(catalog) {
32    this.library =new PublicLibrary(catalog);
33   };
34   // implements Library
35   implements(PublicLibraryProxy,Library);
36
37   PublicLibraryProxy.prototype = {
38    findBooks: function(searchString) {
39    returnthis.library.findBooks(searchString);
40   },
41   checkoutBook: function(book) {
42    returnthis.library.checkoutBook(book);
43    },
44    returnBook: function(book) {
45    returnthis.library.returnBook(book);
46    }
47   };

 

  觀(guān)察者(Observer)模式:定義對象間的一種一對多的依賴(lài)關(guān)系,以便當一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴(lài)于它的對象都得到通知并自動(dòng)刷新。

  觀(guān)察者模式中存在兩個(gè)角色,觀(guān)察者和被觀(guān)察者。在DOM的編程環(huán)境中的高級事件模式中,事件監聽(tīng)器說(shuō)到底就是一種內置的觀(guān)察者。事件處理器(handler)和時(shí)間監聽(tīng)器(listener)并不是一回事,前者就是一種把事件傳給與其關(guān)聯(lián)的函數的手段,而在后者中,一個(gè)時(shí)間可以與幾個(gè)監聽(tīng)器關(guān)聯(lián),每個(gè)監聽(tīng)器都能獨立于其他監聽(tīng)器而改變。

 1   //使用時(shí)間監聽(tīng)器可以讓多個(gè)函數相應一個(gè)事件
2   var fn1 =function(){
3   //code
4   }
5   var fn2 =function(){
6   //code
7   }
8   addEvent(element,'click',fn1);
9   addEvent(element,'click',fn2)
10
11   //而時(shí)間處理函數就辦不到
12   element.onclick = fn1;
13   element.onclick = fn2;

  觀(guān)察者模式是開(kāi)發(fā)基于行為的應用程序的有力手段,前端程序員可做的就是借助一個(gè)事件監聽(tīng)器替你處理各種行為,從而降低內存消耗和提高互動(dòng)性能。

 

  命令(Command)模式:將一個(gè)請求封裝為一個(gè)對象,從而使你可用不同的請求對客戶(hù)進(jìn)行參數化;對請求排隊或記錄請求日志,以及支持可取消的操作。

  命令對象是一個(gè)操作和用來(lái)調用這個(gè)操作的對象的結合體,所有的命名對象都有一個(gè)執行操作,其用途就是調用命令對象所綁定的操作。示例:

 

 1   car Calculator={
2   add:function(x,y){
3    return x+y;
4   },
5   substract:function(x,y){
6    return x-y;
7   },
8   multiply:function(x,y){
9    return x*y;
10   },
11   divide:function(x,y){
12    return x/y;
13   }
14   }
15   Calculator.calc =function(command){
16   return Calculator[command.type](command.op1,command.opd2)
17   };
18   Calculator.calc({type:'add',op1:1,op2:1});
19   Calculator.calc({type:'substract',op1:5,op2:2});
20   Calculator.calc({type:'multiply',op1:5,op2:2});
21   Calculator.calc({type:'divide',op1:8,op2:4});

  命名模式的主要用途是把調用對象(用戶(hù)界面,API和代理等)與實(shí)現操作的對象隔離開(kāi),也就是說(shuō)使對象間的互動(dòng)方式需要更高的模塊化時(shí)都可以用到這種模式。

 

  職責鏈(Chain Of Responsibility)模式:為解除請求的發(fā)送者和接收者之間耦合,而使多個(gè)對象都有機會(huì )處理這個(gè)請求。將這些對象連成一條鏈,并沿著(zhù)這條鏈傳遞該請求,直到有一個(gè)對象處理它。

  職責鏈由多個(gè)不同類(lèi)型的對象組成:發(fā)送者是發(fā)出請求的對象,而接收者則是接收請求并且對其進(jìn)行處理或傳遞的對象,請求本身有時(shí)也是一個(gè)對象,它封裝著(zhù)與操作有關(guān)的所有數據。

  典型的流程大致是:

  1.發(fā)送者知道鏈中第一個(gè)接收者,它向這個(gè)接收者發(fā)出請求。

  2.每一個(gè)接收者都對請求進(jìn)行分析,然后要么處理它,要么將其往下傳。

  3.每一個(gè)接收者知道的其他對象只有一個(gè),即它在鏈中的下家。

  4.如果沒(méi)有任何接收者處理請求,那么請求將從鏈上離開(kāi),不同的實(shí)現對此也有不同的反應,一般會(huì )拋出一個(gè)錯誤。

 

   職責鏈模式的適用范圍:1.有多個(gè)的對象可以處理一個(gè)請求,哪個(gè)對象處理該請求運行時(shí)刻自動(dòng)確定;2.想在不明確指定接收者的情況下,向多個(gè)對象中的一個(gè)提交一個(gè)請求;3.可處理一個(gè)請求的對象集合需要被動(dòng)態(tài)指定。

  確實(shí)對這種模式不了解,相關(guān)資料也較少,所以代碼先不上了??纯创蠹覍@個(gè)模式有木有什么好的理解或者能較好表達這種模式的代碼,謝謝了。

 

 

  結束語(yǔ):

  1.每種模式都有自己的優(yōu)缺點(diǎn),所以每種模式的正確使用還得看開(kāi)發(fā)人員本身的功力;

  2.就算不使用JavaScript設計模式一樣可以寫(xiě)出 復雜的可使用 的代碼,可是如果你想真正了解JavaScript面向對象能力,學(xué)習提高代碼的模塊化程度﹑可維護性﹑可靠性和效率,那么合理的運用JavaScript設計模式將會(huì )是一個(gè)優(yōu)秀 前端開(kāi)發(fā)攻城濕 必備的能力。

  終于在8月31日發(fā)了這篇博客,字很多,辛苦大家了...

  最后,祝大家工作順利。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
JavaScript設計模式
Javascript的this用法
Javascript 嚴格模式use strict詳解
深入理解JavaScript函數及其模式(一)
JavaScript:JavaScript命名空間模式實(shí)例詳解
深入理解JavaScript系列(21):S.O.L.I.D五大原則之接口隔離原則ISP
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久