Javascript設計模式理論與實戰:享元模式

 

享元模式不一樣於通常的設計模式,它主要用來優化程序的性能,它最適合解決大量相似的對象而產生的性能問題。享元模式經過分析應用程序的對象,將其解析爲內在數據和外在數據,減小對象的數量,從而提升應用程序的性能。設計模式

基本知識

享元模式經過共享大量的細粒度的對象,減小對象的數量,從而減小對象的內存,提升應用程序的性能。其基本思想就是分解現有相似對象的組成,將其展開爲能夠共享的內在數據和不可共享的外在數據,咱們稱內在數據的對象爲享元對象。一般還須要一個工廠類來維護內在數據。
在JS中,享元模式主要有下面幾個角色組成:
(1)客戶端:用來調用享元工廠來獲取內在數據的類,一般是應用程序所需的對象,
(2)享元工廠:用來維護享元數據的類
(3)享元類:保持內在數據的類iphone

享元模式的實現和應用

通常實現

咱們舉個例子進行說明:蘋果公司批量生產iphone,iphone的大部分數據好比型號,屏幕都是同樣,少數部分數據好比內存有分16G,32G等。未使用享元模式前,咱們寫代碼以下:函數

 1 function Iphone(model, screen, memory, SN) {
 2     this. model  = model;
 3     this.screen = screen;
 4     this.memory = memory;
 5     this.SN = SN;
 6 }
 7 var phones = [];
 8 for (var i = 0; i < 1000000; i++) {
 9     var memory = i % 2 == 0 ? 16 : 32;
10     phones.push(new Iphone("iphone6s", 5.0, memory, i));
11 }

這段代碼中,建立了一百萬個iphone,每一個iphone都獨立申請一個內存。可是咱們仔細觀察能夠看到,大部分iphone都是相似的,只是內存和序列號不同,若是是一個對性能要求比較高的程序,咱們就要考慮去優化它。
大量類似對象的程序,咱們就能夠考慮用享元模式去優化它,咱們分析出大部分的iphone的型號,屏幕,內存都是同樣的,那這部分數據就能夠公用,就是享元模式中的內在數據,定義享元類以下:性能

1 function IphoneFlyweight(model, screen, memory) {
2     this.model = model;
3     this.screen = screen;
4     this.memory = memory;
5 }

咱們定義了iphone的享元類,其中包含型號,屏幕和內存三個數據。咱們還須要一個享元工廠來維護這些數據:優化

 1 var flyweightFactory = (function () {
 2     var iphones = {};
 3     return {
 4         get: function (model, screen, memory) {
 5             var key = model + screen + memory;
 6             if (!iphones[key]) {
 7                 iphones[key] = new IphoneFlyweight(model, screen, memory);
 8             }
 9             return iphones[key];
10         }
11     };
12 })();

在這個工廠中,咱們定義了一個字典來保存享元對象,提供一個方法根據參數來獲取享元對象,若是字典中有則直接返回,沒有則建立一個返回。
接着咱們建立一個客戶端類,這個客戶端類就是修改自iphone類:this

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

而後咱們依舊像之間那樣生成多個iphonespa

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

這裏的關鍵就在於Iphone構造函數裏面的this.flyweight = flyweightFactory.get(model, screen, memory)。這句代碼經過享元工廠去獲取享元數據,而在享元工廠裏面,若是已經存在相同數據的對象則會直接返回對象,多個iphone對象共享這部分相同的數據,因此本來相似的數據已經大大減小,減小的內存的佔用。設計

享元模式在DOM中的應用

享元模式的一個典型應用就是DOM事件操做,DOM事件機制分紅事件冒泡和事件捕獲。咱們簡單介紹一下這二者:
事件冒泡:綁定的事件從最裏層的元素開始觸發,而後冒泡到最外層
事件捕獲:綁定的事件從最外層的元素開始觸發,而後傳到最裏層
假設咱們HTML中有一個菜單列表code

1 <ul class="menu">
2     <li class="item">選項1</li>
3     <li class="item">選項2</li>
4     <li class="item">選項3</li>
5     <li class="item">選項4</li>
6     <li class="item">選項5</li>
7     <li class="item">選項6</li>
8 </ul>

點擊菜單項,進行相應的操做,咱們經過jQuery來綁定事件,通常會這麼作:對象

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

給每一個列表項綁定事件,點擊輸出相應的文本。這樣看暫時沒有什麼問題,可是若是是一個很長的列表,尤爲是在移動端特別長的列表時,就會有性能問題,由於每一個項都綁定了事件,都佔用了內存。可是這些事件處理程序其實都是很相似的,咱們就要對其優化。

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

經過這種方式進行事件綁定,能夠減小事件處理程序的數量,這種方式叫作事件委託,也是運用了享元模式的原理。事件處理程序是公用的內在部分,每一個菜單項各自的文本就是外在部分。咱們簡單說下事件委託的原理:點擊菜單項,事件會從li元素冒泡到ul元素,咱們綁定事件到ul上,實際上就綁定了一個事件,而後經過事件參數event裏面的target來判斷點擊的具體是哪個元素,好比低級第一個li元素,event.target就是li,這樣就能拿到具體的點擊元素了,就能夠根據不一樣元素進行不一樣的處理。

總結

享元模式是一種優化程序性能的手段,經過共享公用數據來減小對象數量以達到優化程序的手段。享元模式適用於擁有大量相似對象而且對性能有要求的場景。由於享元模式須要分離內部和外部數據,增長了程序的邏輯複雜性,建議對性能有要求的時候才使用享元模式。

原文地址:http://luopq.com/2015/11/20/design-pattern-flyweight/

相關文章
相關標籤/搜索