欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

總結(jié)JavaScript設(shè)計(jì)模式編程中的享元模式使用

 更新時(shí)間:2016年05月21日 10:10:03   作者:狼狼的藍(lán)胖子  
享元模式最適合于解決因創(chuàng)建大量類似對(duì)象而累及性能的問(wèn)題,本文將來(lái)總結(jié)JavaScript設(shè)計(jì)模式編程中的享元模式使用,包括在DOM操作時(shí)的利用示例:

享元模式不同于一般的設(shè)計(jì)模式,它主要用來(lái)優(yōu)化程序的性能,它最適合解決大量類似的對(duì)象而產(chǎn)生的性能問(wèn)題。享元模式通過(guò)分析應(yīng)用程序的對(duì)象,將其解析為內(nèi)在數(shù)據(jù)和外在數(shù)據(jù),減少對(duì)象的數(shù)量,從而提高應(yīng)用程序的性能。

基本知識(shí)

享元模式通過(guò)共享大量的細(xì)粒度的對(duì)象,減少對(duì)象的數(shù)量,從而減少對(duì)象的內(nèi)存,提高應(yīng)用程序的性能。其基本思想就是分解現(xiàn)有類似對(duì)象的組成,將其展開(kāi)為可以共享的內(nèi)在數(shù)據(jù)和不可共享的外在數(shù)據(jù),我們稱內(nèi)在數(shù)據(jù)的對(duì)象為享元對(duì)象。通常還需要一個(gè)工廠類來(lái)維護(hù)內(nèi)在數(shù)據(jù)。
在JS中,享元模式主要有下面幾個(gè)角色組成:
(1)客戶端:用來(lái)調(diào)用享元工廠來(lái)獲取內(nèi)在數(shù)據(jù)的類,通常是應(yīng)用程序所需的對(duì)象,
(2)享元工廠:用來(lái)維護(hù)享元數(shù)據(jù)的類
(3)享元類:保持內(nèi)在數(shù)據(jù)的類

享元模式的實(shí)現(xiàn)和應(yīng)用

一般實(shí)現(xiàn)

我們舉個(gè)例子進(jìn)行說(shuō)明:蘋(píng)果公司批量生產(chǎn)iphone,iphone的大部分?jǐn)?shù)據(jù)比如型號(hào),屏幕都是一樣,少數(shù)部分?jǐn)?shù)據(jù)比如內(nèi)存有分16G,32G等。未使用享元模式前,我們寫(xiě)代碼如下:

function Iphone(model, screen, memory, SN) {
  this. model = model;
  this.screen = screen;
  this.memory = memory;
  this.SN = SN;
}
var phones = [];
for (var i = 0; i < 1000000; i++) {
  var memory = i % 2 == 0 ? 16 : 32;
  phones.push(new Iphone("iphone6s", 5.0, memory, i));
}

這段代碼中,創(chuàng)建了一百萬(wàn)個(gè)iphone,每個(gè)iphone都獨(dú)立申請(qǐng)一個(gè)內(nèi)存。但是我們仔細(xì)觀察可以看到,大部分iphone都是類似的,只是內(nèi)存和序列號(hào)不一樣,如果是一個(gè)對(duì)性能要求比較高的程序,我們就要考慮去優(yōu)化它。
大量相似對(duì)象的程序,我們就可以考慮用享元模式去優(yōu)化它,我們分析出大部分的iphone的型號(hào),屏幕,內(nèi)存都是一樣的,那這部分?jǐn)?shù)據(jù)就可以公用,就是享元模式中的內(nèi)在數(shù)據(jù),定義享元類如下:

function IphoneFlyweight(model, screen, memory) {
  this.model = model;
  this.screen = screen;
  this.memory = memory;
}

我們定義了iphone的享元類,其中包含型號(hào),屏幕和內(nèi)存三個(gè)數(shù)據(jù)。我們還需要一個(gè)享元工廠來(lái)維護(hù)這些數(shù)據(jù):

 var flyweightFactory = (function () {
  var iphones = {};
  return {
    get: function (model, screen, memory) {
      var key = model + screen + memory;
      if (!iphones[key]) {
        iphones[key] = new IphoneFlyweight(model, screen, memory);
      }
      return iphones[key];
    }
  };
})();

在這個(gè)工廠中,我們定義了一個(gè)字典來(lái)保存享元對(duì)象,提供一個(gè)方法根據(jù)參數(shù)來(lái)獲取享元對(duì)象,如果字典中有則直接返回,沒(méi)有則創(chuàng)建一個(gè)返回。
接著我們創(chuàng)建一個(gè)客戶端類,這個(gè)客戶端類就是修改自iphone類:

 function Iphone(model, screen, memory, SN) {
  this.flyweight = flyweightFactory.get(model, screen, memory);
  this.SN = SN;
}

然后我們依舊像之間那樣生成多個(gè)iphone

var phones = [];
for (var i = 0; i < 1000000; i++) {
  var memory = i % 2 == 0 ? 16 : 32;
  phones.push(new Iphone("iphone6s", 5.0, memory, i));
}
console.log(phones);

這里的關(guān)鍵就在于Iphone構(gòu)造函數(shù)里面的this.flyweight = flyweightFactory.get(model, screen, memory)。這句代碼通過(guò)享元工廠去獲取享元數(shù)據(jù),而在享元工廠里面,如果已經(jīng)存在相同數(shù)據(jù)的對(duì)象則會(huì)直接返回對(duì)象,多個(gè)iphone對(duì)象共享這部分相同的數(shù)據(jù),所以原本類似的數(shù)據(jù)已經(jīng)大大減少,減少的內(nèi)存的占用。

享元模式在DOM中的應(yīng)用

享元模式的一個(gè)典型應(yīng)用就是DOM事件操作,DOM事件機(jī)制分成事件冒泡和事件捕獲。我們簡(jiǎn)單介紹一下這兩者:
事件冒泡:綁定的事件從最里層的元素開(kāi)始觸發(fā),然后冒泡到最外層
事件捕獲:綁定的事件從最外層的元素開(kāi)始觸發(fā),然后傳到最里層
假設(shè)我們HTML中有一個(gè)菜單列表

<ul class="menu">
  <li class="item">選項(xiàng)1</li>
  <li class="item">選項(xiàng)2</li>
  <li class="item">選項(xiàng)3</li>
  <li class="item">選項(xiàng)4</li>
  <li class="item">選項(xiàng)5</li>
  <li class="item">選項(xiàng)6</li>
</ul>

點(diǎn)擊菜單項(xiàng),進(jìn)行相應(yīng)的操作,我們通過(guò)jQuery來(lái)綁定事件,一般會(huì)這么做:

$(".item").on("click", function () {
  console.log($(this).text());
})

給每個(gè)列表項(xiàng)綁定事件,點(diǎn)擊輸出相應(yīng)的文本。這樣看暫時(shí)沒(méi)有什么問(wèn)題,但是如果是一個(gè)很長(zhǎng)的列表,尤其是在移動(dòng)端特別長(zhǎng)的列表時(shí),就會(huì)有性能問(wèn)題,因?yàn)槊總€(gè)項(xiàng)都綁定了事件,都占用了內(nèi)存。但是這些事件處理程序其實(shí)都是很類似的,我們就要對(duì)其優(yōu)化。

$(".menu").on("click", ".item", function () {
  console.log($(this).text());
})

通過(guò)這種方式進(jìn)行事件綁定,可以減少事件處理程序的數(shù)量,這種方式叫做事件委托,也是運(yùn)用了享元模式的原理。事件處理程序是公用的內(nèi)在部分,每個(gè)菜單項(xiàng)各自的文本就是外在部分。我們簡(jiǎn)單說(shuō)下事件委托的原理:點(diǎn)擊菜單項(xiàng),事件會(huì)從li元素冒泡到ul元素,我們綁定事件到ul上,實(shí)際上就綁定了一個(gè)事件,然后通過(guò)事件參數(shù)event里面的target來(lái)判斷點(diǎn)擊的具體是哪一個(gè)元素,比如低級(jí)第一個(gè)li元素,event.target就是li,這樣就能拿到具體的點(diǎn)擊元素了,就可以根據(jù)不同元素進(jìn)行不同的處理。

總結(jié)

享元模式是一種優(yōu)化程序性能的手段,通過(guò)共享公用數(shù)據(jù)來(lái)減少對(duì)象數(shù)量以達(dá)到優(yōu)化程序的手段。享元模式適用于擁有大量類似對(duì)象并且對(duì)性能有要求的場(chǎng)景。因?yàn)橄碓J叫枰蛛x內(nèi)部和外部數(shù)據(jù),增加了程序的邏輯復(fù)雜性,建議對(duì)性能有要求的時(shí)候才使用享元模式。

享元模式之利:
可以把網(wǎng)頁(yè)的資源符合降低幾個(gè)數(shù)量級(jí)。即使享元模式的應(yīng)用無(wú)法將實(shí)例的個(gè)數(shù)削減到一個(gè),你仍能夠從中獲益不少。

這種節(jié)省不需要大量修改原有代碼。在創(chuàng)建了管理器、工廠和享元之后,就需要對(duì)代碼進(jìn)行的修改只不過(guò)是從直接實(shí)例化目標(biāo)類改為調(diào)用管理器對(duì)象的某個(gè)方法。

享元模式之弊:
如果把它用在不必要的地方,其結(jié)果反而有損代碼的運(yùn)行效率。這種模式在優(yōu)化代碼的同時(shí),也提高了其復(fù)雜程度,這會(huì)給調(diào)試和維護(hù)造成困難。

它之所以會(huì)妨礙調(diào)試,是因?yàn)楝F(xiàn)在可能出錯(cuò)的地方變成了三個(gè):管理器、工廠和享元。

這種優(yōu)化也會(huì)使維護(hù)變得更加困難?,F(xiàn)在你面對(duì)的不是由封裝著數(shù)據(jù)的對(duì)象構(gòu)成的清晰架構(gòu),而是一堆又碎又亂的東西。其中的數(shù)據(jù)至少分兩處保存。最好注釋標(biāo)明內(nèi)在數(shù)據(jù)和外在數(shù)據(jù)。

只有在必要的時(shí)候才應(yīng)該進(jìn)行這種優(yōu)化。必須在運(yùn)行效率和可維護(hù)性之間進(jìn)行權(quán)衡。如果拿不準(zhǔn)是否需要使用享元模式,那么你很可能并不需要它。享元模式適合的是系統(tǒng)資源已經(jīng)用得差不多而且明顯需要進(jìn)行某種優(yōu)化這樣一類場(chǎng)合。

這種模式對(duì)Javascript程序員特別有用,因?yàn)樗梢杂脕?lái)減少網(wǎng)頁(yè)上所要使用的DOM元素的數(shù)量,要知道這些元素需要耗費(fèi)許多內(nèi)存。結(jié)合使用這種模式與組合模式等組織型可以開(kāi)發(fā)出功能豐富的復(fù)雜Web應(yīng)用系統(tǒng),它們可以平穩(wěn)的運(yùn)行在任何現(xiàn)代Javascript環(huán)境中。

享元模式的適用場(chǎng)合:
網(wǎng)頁(yè)中必須使用了大量資源密集型對(duì)象。如果只會(huì)用到少許這類對(duì)象,這種優(yōu)化并不劃算。

對(duì)象中所保存的數(shù)據(jù)至少有一部分能被轉(zhuǎn)化為外在數(shù)據(jù)。此外,將這些數(shù)據(jù)存儲(chǔ)在對(duì)象外部所占用的資源應(yīng)該相對(duì)較少,否則這種做法對(duì)于性能的提示實(shí)際上毫無(wú)意義。那種大量包含基礎(chǔ)性代碼和HTML內(nèi)容的對(duì)象可能比較適合這種優(yōu)化。

將外在數(shù)據(jù)分離出去后,獨(dú)一無(wú)二的對(duì)象的數(shù)目相對(duì)較少。

相關(guān)文章

最新評(píng)論