亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入理解JavaScript系列(37):設計模式之享元模式詳解

2019-11-20 13:01:42
字體:
來源:轉載
供稿:網友

介紹

享元模式(Flyweight),運行共享技術有效地支持大量細粒度的對象,避免大量擁有相同內容的小類的開銷(如耗費內存),使大家共享一個類(元類)。

享元模式可以避免大量非常相似類的開銷,在程序設計中,有時需要生產大量細粒度的類實例來表示數據,如果能發現這些實例除了幾個參數以外,開銷基本相同的 話,就可以大幅度較少需要實例化的類的數量。如果能把那些參數移動到類實例的外面,在方法調用的時候將他們傳遞進來,就可以通過共享大幅度第減少單個實例 的數目。

那么如果在JavaScript中應用享元模式呢?有兩種方式,第一種是應用在數據層上,主要是應用在內存里大量相似的對象上;第二種是應用在DOM層上,享元可以用在中央事件管理器上用來避免給父容器里的每個子元素都附加事件句柄。

享元與數據層

Flyweight中有兩個重要概念--內部狀態intrinsic和外部狀態extrinsic之分,內部狀態就是在對象里通過內部方法管理,而外部信息可以在通過外部刪除或者保存。

說白點,就是先捏一個的原始模型,然后隨著不同場合和環境,再產生各具特征的具體模型,很顯然,在這里需要產生不同的新對象,所以Flyweight模式中常出現Factory模式,Flyweight的內部狀態是用來共享的,Flyweight factory負責維護一個Flyweight pool(模式池)來存放內部狀態的對象。

使用享元模式

讓我們來演示一下如果通過一個類庫讓系統來管理所有的書籍,每個書籍的元數據暫定為如下內容:

復制代碼 代碼如下:

ID
Title
Author
Genre
Page count
Publisher ID
ISBN

我們還需要定義每本書被借出去的時間和借書人,以及退書日期和是否可用狀態:
復制代碼 代碼如下:

checkoutDate
checkoutMember
dueReturnDate
availability

因為book對象設置成如下代碼,注意該代碼還未被優化:
復制代碼 代碼如下:

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;
   },
/*其它get方法在這里就不顯示了*/

// 更新借出狀態
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對象在內存里可想而知,我們需要用享元模式來優化。

我們可以將數據分成內部和外部兩種數據,和book對象相關的數據(title, author 等)可以歸結為內部屬性,而(checkoutMember, dueReturnDate等)可以歸結為外部屬性。這樣,如下代碼就可以在同一本書里共享同一個對象了,因為不管誰借的書,只要書是同一本書,基本信息是一樣的:

復制代碼 代碼如下:

/*享元模式優化代碼*/
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的對象,如果有就返回,沒有就重新創建并存儲以便后面可以繼續訪問,這確保我們為每一種書只創建一個對象:

復制代碼 代碼如下:

/* Book工廠 單例 */
var BookFactory = (function(){
   var existingBooks = {};
   return{
       createBook: function(title, author, genre,pageCount,publisherID,ISBN){
       /*查找之前是否創建*/
           var existingBook = existingBooks[ISBN];
           if(existingBook){
                   return existingBook;
               }else{
               /* 如果沒有,就創建一個,然后保存*/
               var book = new Book(title, author, genre,pageCount,publisherID,ISBN);
               existingBooks[ISBN] =  book;
               return book;
           }
       }
   }
});

管理外部狀態
外部狀態,相對就簡單了,除了我們封裝好的book,其它都需要在這里管理:
復制代碼 代碼如下:

/*BookRecordManager 借書管理類 單例*/
var BookRecordManager = (function(){
   var bookRecordDatabase = {};
   return{
       /*添加借書記錄*/
       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);
   }
 };
});


通過這種方式,我們做到了將同一種圖書的相同信息保存在一個bookmanager對象里,而且只保存一份;相比之前的代碼,就可以發現節約了很多內存。

享元模式與DOM

關于DOM的事件冒泡,在這里就不多說了,相信大家都已經知道了,我們舉兩個例子。

例1:事件集中管理

舉例來說,如果我們又很多相似類型的元素或者結構(比如菜單,或者ul里的多個li)都需要監控他的click事件的話,那就需要多每個元素進行事件綁定,如果元素有非常非常多,那性能就可想而知了,而結合冒泡的知識,任何一個子元素有事件觸發的話,那觸發以后事件將冒泡到上一級元素,所以利用這個特性,我們可以使用享元模式,我們可以對這些相似元素的父級元素進行事件監控,然后再判斷里面哪個子元素有事件觸發了,再進行進一步的操作。

在這里我們結合一下jQuery的bind/unbind方法來舉例。

HTML:

復制代碼 代碼如下:

<div id="container">
   <div class="toggle" href="#">更多信息 (地址)
       <span class="info">
          這里是更多信息
       </span></div>
   <div class="toggle" href="#">更多信息 (地圖)
       <span class="info">
          <iframe src="http://www.map-generator.net/extmap.php?name=London&address=london%2C%20england&width=500...gt;"</iframe>
       </span>
   </div>
</div>

JavaScript:
復制代碼 代碼如下:

stateManager = {
   fly: function(){
       var self =  this;
       $('#container').unbind().bind("click", function(e){
           var target = $(e.originalTarget || e.srcElement);
           // 判斷是哪一個子元素
           if(target.is("div.toggle")){
               self.handleClick(target);
           }
       });
   },

   handleClick: function(elem){
       elem.find('span').toggle('slow');
   }
});

例2:應用享元模式提升性能

另外一個例子,依然和jQuery有關,一般我們在事件的回調函數里使用元素對象是會后,經常會用到$(this)這種形式,其實它重復創建了新對象,因為本身回調函數里的this已經是DOM元素自身了,我們必要必要使用如下這樣的代碼:

復制代碼 代碼如下:

$('div').bind('click', function(){
 console.log('You clicked: ' + $(this).attr('id'));
});
// 上面的代碼,要避免使用,避免再次對DOM元素進行生成jQuery對象,因為這里可以直接使用DOM元素自身了。
$('div').bind('click', function(){
 console.log('You clicked: ' + this.id);
});

其實,如果非要用$(this)這樣的形式,我們也可以實現自己版本的單實例模式,比如我們來實現一個jQuery.signle(this)這樣的函數以便返回DOM元素自身:
復制代碼 代碼如下:

jQuery.single = (function(o){

   var collection = jQuery([1]);
   return function(element) {

       // 將元素放到集合里
       collection[0] = element;

        // 返回集合
       return collection;

   };
 });
 


使用方法:
復制代碼 代碼如下:

$('div').bind('click', function(){
   var html = jQuery.single(this).next().html();
   console.log(html);
 });

這樣,就是原樣返回DOM元素自身了,而且不進行jQuery對象的創建。

總結

Flyweight模式是一個提高程序效率和性能的模式,會大大加快程序的運行速度.應用場合很多:比如你要從一個數據庫中讀取一系列字符串,這些字符串中有許多是重復的,那么我們可以將這些字符串儲存在Flyweight池(pool)中。

如果一個應用程序使用了大量的對象,而這些大量的對象造成了很大的存儲開心時就應該考慮使用享元模式;還有就是對象的大多數狀態可以外部狀態,如果刪除對象的外部狀態,那么就可以用相對較少的共享對象取代很多組對象,此時可以考慮使用享元模式。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲精品久久久久久下一站| 成人网址在线观看| 91精品国产高清| 欧美夜福利tv在线| 欧美性xxxx极品hd满灌| 久色乳综合思思在线视频| 欧美一级淫片aaaaaaa视频| 国产成人高清激情视频在线观看| 久久久97精品| 欧美日韩精品在线| 成人午夜在线视频一区| 亚洲国产美女精品久久久久∴| 尤物九九久久国产精品的分类| 久久免费国产精品1| 奇门遁甲1982国语版免费观看高清| 久久久久久久999| 中文字幕久久久| 亚洲毛片一区二区| 日韩电影免费观看中文字幕| 亚洲va电影大全| 最近2019中文字幕大全第二页| 亚洲xxxx视频| 91精品啪在线观看麻豆免费| 欧美在线视频免费观看| 这里只有精品在线观看| 亚洲最大成人网色| 91人人爽人人爽人人精88v| 成人免费大片黄在线播放| 66m—66摸成人免费视频| 亚洲国产91精品在线观看| 国外视频精品毛片| 亚洲国产精品va在线看黑人动漫| 亚洲激情视频在线观看| 亚洲一区二区在线| 中文字幕日韩免费视频| 欧美日韩一区二区在线播放| 欧美一区二区三区免费视| 精品国产福利在线| 欧美性xxxx18| 欧美激情中文字幕乱码免费| 91免费欧美精品| 亚洲va国产va天堂va久久| 97人洗澡人人免费公开视频碰碰碰| 51午夜精品视频| 久久久之久亚州精品露出| 色青青草原桃花久久综合| 亚洲精品网站在线播放gif| 国产一区二区激情| 色婷婷综合久久久久中文字幕1| 欧美日韩国产中文字幕| 日韩av片电影专区| 国产精品成人aaaaa网站| 久久久亚洲网站| 成人黄在线观看| 中文字幕欧美日韩精品| 亚洲精品v欧美精品v日韩精品| 欧美性猛交xxxx黑人| 亚洲精品成人久久| 久久视频中文字幕| 97国产精品视频人人做人人爱| 亚洲深夜福利在线| 欧美日韩中国免费专区在线看| 日韩免费观看在线观看| 91精品国产乱码久久久久久久久| 中文字幕v亚洲ⅴv天堂| 欧美在线一级视频| 久久久精品网站| 成人精品一区二区三区电影黑人| 亚洲综合精品伊人久久| 日韩国产精品亚洲а∨天堂免| 国产精品夜色7777狼人| 国产91露脸中文字幕在线| 成人网在线免费观看| 91av在线网站| 亚洲午夜未满十八勿入免费观看全集| 欧美一级黑人aaaaaaa做受| 中文综合在线观看| 在线观看欧美视频| 亚洲а∨天堂久久精品喷水| 国产精品自在线| 欧美日韩成人在线观看| 成人av在线天堂| 欧美成人免费大片| 日韩美女视频免费看| 91视频-88av| 亚洲精品综合精品自拍| 粉嫩av一区二区三区免费野| 黄色成人在线免费| 亚洲激情视频在线| 国产伊人精品在线| 精品久久久久久久中文字幕| 日韩一区二区福利| 最近2019免费中文字幕视频三| 久久成人免费视频| 国产99久久精品一区二区 夜夜躁日日躁| 日韩av在线影院| 青青精品视频播放| 欧美寡妇偷汉性猛交| 久久影视电视剧凤归四时歌| 国产主播喷水一区二区| 一本色道久久88综合日韩精品| 久久免费视频网站| 亚洲黄色免费三级| www国产精品视频| 韩国一区二区电影| 欧美国产日本高清在线| 夜夜嗨av一区二区三区四区| 九九热这里只有在线精品视| 国产一区二区在线免费| 亚洲精品中文字幕有码专区| 成人免费xxxxx在线观看| 国产精品嫩草影院久久久| 亚洲国内精品视频| 久久久久免费精品国产| 欧美国产精品va在线观看| 久久人人爽人人| 岛国av一区二区在线在线观看| 国产主播在线一区| 精品视频在线播放| 97色在线观看免费视频| 亚洲欧美日韩中文在线制服| 中文字幕日韩av综合精品| 久久91亚洲精品中文字幕奶水| 国产日韩精品视频| 亚洲开心激情网| 欧美视频在线观看免费| 欧美黄色片在线观看| 国产综合色香蕉精品| 97人人爽人人喊人人模波多| 国产美女久久久| 国外色69视频在线观看| 蜜臀久久99精品久久久无需会员| 91久久久久久久久| 欧美夫妻性生活视频| 色先锋资源久久综合5566| 欧美在线日韩在线| 亚洲一区二区三区777| 国产精品日韩电影| 欧美日本精品在线| 91香蕉亚洲精品| 欧美国产日韩精品| 精品国产福利视频| 国产精品中文字幕在线| 欧美精品日韩三级| 黄色成人在线免费| 亚洲视频在线看| 中文字幕在线成人| 色yeye香蕉凹凸一区二区av| 亚洲在线视频观看| 亚洲电影免费观看| 国产免费成人av| 亚洲国产精品久久久久秋霞不卡| 国产精品自拍小视频| 国产精品视频xxx| 精品国产精品三级精品av网址| 欧美性猛交xxxx偷拍洗澡| 欧美福利视频网站| 国产成人小视频在线观看| 中文字幕日本欧美| 国产激情久久久久| 中日韩午夜理伦电影免费| 国产成人啪精品视频免费网| 69精品小视频| 国内外成人免费激情在线视频网站|