享元模式

Flyweight
目的
服用小而多的對象,減少內(nèi)存使用。
何時(shí)使用
- 對象太多消耗內(nèi)存
- 大部分對象的狀態(tài)是外在的(和對象本身無關(guān))
- 用一些共享的對象代替大量對象
代碼
http://codepen.io/staskh/pen/xEEwmN?editors=0010
首先看一個(gè)非享元模式,看看我們?nèi)绾胃倪M(jìn)下面這個(gè)例子
/**
* Created by shenyin.sy on 17/3/23.
*/
var Book = function( id, title, author, genre, pageCount,publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate,availability ){
this.id = id;
this.title = title;
this.author = author;
this.genre = genre;
this.pageCount = pageCount;
this.publisherID = publisherID;
this.ISBN = ISBN;
this.checkoutDate = checkoutDate;
this.checkoutMember = checkoutMember;
this.dueReturnDate = dueReturnDate;
this.availability = availability;
};
Book.prototype = {
getTitle: function () {
return this.title;
},
getAuthor: function () {
return this.author;
},
getISBN: function (){
return this.ISBN;
},
// For brevity, other getters are not shown
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 );
}
};
我們看到例子中的書本,關(guān)鍵的屬性是
this.id = id;
this.title = title;
this.author = author;
this.genre = genre;
this.pageCount = pageCount;
this.publisherID = publisherID;
this.ISBN = ISBN;
和書本身無關(guān)的屬性是
this.checkoutDate = checkoutDate;
this.checkoutMember = checkoutMember;
this.dueReturnDate = dueReturnDate;
this.availability = availability;
現(xiàn)在每次創(chuàng)建一個(gè)書本對象,都會(huì)創(chuàng)建上面的屬性。
看看改進(jìn)版。
// Flyweight optimized version
var Book = function ( title, author, genre, pageCount, publisherID, ISBN ) {
this.title = title;
this.author = author;
this.genre = genre;
this.pageCount = pageCount;
this.publisherID = publisherID;
this.ISBN = ISBN;
};
// Book Factory singleton
var BookFactory = (function () {
var existingBooks = {}, existingBook;
return {
createBook: function ( title, author, genre, pageCount, publisherID, ISBN ) {
// Find out if a particular book meta-data combination has been created before
// !! or (bang bang) forces a boolean to be returned
existingBook = existingBooks[ISBN];
if ( !!existingBook ) {
return existingBook;
} else {
// if not, let's create a new instance of the book and store it
var book = new Book( title, author, genre, pageCount, publisherID, ISBN );
existingBooks[ISBN] = book;
return book;
}
}
};
})();
// BookRecordManager singleton
var BookRecordManager = (function () {
var bookRecordDatabase = {};
return {
// add a new book into the library system
addBookRecord: function ( id, title, author, genre, pageCount, publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate, availability ) {
var book = BookFactory.createBook( title, author, genre, pageCount, publisherID, ISBN );
bookRecordDatabase[id] = {
checkoutMember: checkoutMember,
checkoutDate: checkoutDate,
dueReturnDate: dueReturnDate,
availability: availability,
book: 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 );
}
};
})();
改進(jìn)點(diǎn)在于,創(chuàng)建書本的時(shí)候,并不需要借書的信息,圖書館又可能又很多書,同樣ISBN的書屬性又都一樣。
- 創(chuàng)建書的時(shí)候用ISBN
- 借書的時(shí)候用bookID
- 共享了相同書本身的屬性,節(jié)約了內(nèi)存。
技術(shù)上的例子
上面的設(shè)計(jì)模式是一個(gè)業(yè)務(wù)邏輯的例子,看看在我們?nèi)粘J褂玫膸熘校袥]有這樣的思想。
可以看一下這個(gè)測評:
http://jsperf.com/jquery-fly/3
$("div").on( "click", function () {
console.log( "You clicked: " + $( this ).attr( "id" ));
});
// we should avoid using the DOM element to create a
// jQuery object (with the overhead that comes with it)
// and just use the DOM element itself like this:
$( "div" ).on( "click", function () {
console.log( "You clicked:" + this.id );
});
沒必要每次都用DOM創(chuàng)建一個(gè)Jquery對象。
結(jié)論
其實(shí)UI庫中往往有這個(gè)模式,像控件都有一些可以共享的屬性,比如主題顏色等,有一些根據(jù)情況增加的屬性,比如綁定的事件,名字等,所以在比較大的系統(tǒng)中,這個(gè)模式還是很有用的,能節(jié)省不少內(nèi)存。