介紹
享元模式(Flyweight),運行共享技術有效地支持大量細粒度的對象,避免大量擁有相同內容的小類的開銷(如耗費內存),使大家共享一個類(元類)。
享元模式可以避免大量非常相似類的開銷,在程序設計中,有時需要生產大量細粒度的類實例來表示數據,如果能發現這些實例除了幾個參數以外,開銷基本相同的 話,就可以大幅度較少需要實例化的類的數量。如果能把那些參數移動到類實例的外面,在方法調用的時候將他們傳遞進來,就可以通過共享大幅度第減少單個實例 的數目。
那么如果在JavaScript中應用享元模式呢?有兩種方式,第一種是應用在數據層上,主要是應用在內存里大量相似的對象上;第二種是應用在DOM層上,享元可以用在中央事件管理器上用來避免給父容器里的每個子元素都附加事件句柄。
享元與數據層
Flyweight中有兩個重要概念--內部狀態intrinsic和外部狀態extrinsic之分,內部狀態就是在對象里通過內部方法管理,而外部信息可以在通過外部刪除或者保存。
說白點,就是先捏一個的原始模型,然后隨著不同場合和環境,再產生各具特征的具體模型,很顯然,在這里需要產生不同的新對象,所以Flyweight模式中常出現Factory模式,Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個Flyweight pool(模式池)來存放內部狀態的對象。
使用享元模式
讓我們來演示一下如果通過一個類庫讓系統來管理所有的書籍,每個書籍的元數據暫定為如下內容:
// 更新借出狀態
updateCheckoutStatus: function(bookID, newStatus, checkoutDate,checkoutMember, newReturnDate){
this.id = bookID;
this.availability = newStatus;
this.checkoutDate = checkoutDate;
this.checkoutMember = checkoutMember;
this.dueReturnDate = newReturnDate;
},
//續借
extendCheckoutPeriod: function(bookID, newReturnDate){
this.id = bookID;
this.dueReturnDate = newReturnDate;
},
//是否到期
isPastDue: function(bookID){
var currentDate = new Date();
return currentDate.getTime() > Date.parse(this.dueReturnDate);
}
};
我們可以將數據分成內部和外部兩種數據,和book對象相關的數據(title, author 等)可以歸結為內部屬性,而(checkoutMember, dueReturnDate等)可以歸結為外部屬性。這樣,如下代碼就可以在同一本書里共享同一個對象了,因為不管誰借的書,只要書是同一本書,基本信息是一樣的:
定義基本工廠
讓我們來定義一個基本工廠,用來檢查之前是否創建該book的對象,如果有就返回,沒有就重新創建并存儲以便后面可以繼續訪問,這確保我們為每一種書只創建一個對象:
};
},
updateCheckoutStatus: function(bookID, newStatus, checkoutDate, checkoutMember, newReturnDate){
var record = bookRecordDatabase[bookID];
record.availability = newStatus;
record.checkoutDate = checkoutDate;
record.checkoutMember = checkoutMember;
record.dueReturnDate = newReturnDate;
},
extendCheckoutPeriod: function(bookID, newReturnDate){
bookRecordDatabase[bookID].dueReturnDate = newReturnDate;
},
isPastDue: function(bookID){
var currentDate = new Date();
return currentDate.getTime() > Date.parse(bookRecordDatabase[bookID].dueReturnDate);
}
};
});
享元模式與DOM
關于DOM的事件冒泡,在這里就不多說了,相信大家都已經知道了,我們舉兩個例子。
例1:事件集中管理
舉例來說,如果我們又很多相似類型的元素或者結構(比如菜單,或者ul里的多個li)都需要監控他的click事件的話,那就需要多每個元素進行事件綁定,如果元素有非常非常多,那性能就可想而知了,而結合冒泡的知識,任何一個子元素有事件觸發的話,那觸發以后事件將冒泡到上一級元素,所以利用這個特性,我們可以使用享元模式,我們可以對這些相似元素的父級元素進行事件監控,然后再判斷里面哪個子元素有事件觸發了,再進行進一步的操作。
在這里我們結合一下jQuery的bind/unbind方法來舉例。
HTML:
handleClick: function(elem){
elem.find('span').toggle('slow');
}
});
例2:應用享元模式提升性能
另外一個例子,依然和jQuery有關,一般我們在事件的回調函數里使用元素對象是會后,經常會用到$(this)這種形式,其實它重復創建了新對象,因為本身回調函數里的this已經是DOM元素自身了,我們必要必要使用如下這樣的代碼:
var collection = jQuery([1]);
return function(element) {
// 將元素放到集合里
collection[0] = element;
// 返回集合
return collection;
};
});
總結
Flyweight模式是一個提高程序效率和性能的模式,會大大加快程序的運行速度.應用場合很多:比如你要從一個數據庫中讀取一系列字符串,這些字符串中有許多是重復的,那么我們可以將這些字符串儲存在Flyweight池(pool)中。
如果一個應用程序使用了大量的對象,而這些大量的對象造成了很大的存儲開心時就應該考慮使用享元模式;還有就是對象的大多數狀態可以外部狀態,如果刪除對象的外部狀態,那么就可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式。
新聞熱點
疑難解答