<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      深入理解JavaScript系列(37):設(shè)計(jì)模式之享元模式

      2012-04-09 08:46  湯姆大叔  閱讀(15322)  評論(10)    收藏  舉報(bào)

      介紹

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

      享元模式可以避免大量非常相似類的開銷,在程序設(shè)計(jì)中,有時(shí)需要生產(chǎn)大量細(xì)粒度的類實(shí)例來表示數(shù)據(jù),如果能發(fā)現(xiàn)這些實(shí)例除了幾個(gè)參數(shù)以外,開銷基本相同的 話,就可以大幅度較少需要實(shí)例化的類的數(shù)量。如果能把那些參數(shù)移動(dòng)到類實(shí)例的外面,在方法調(diào)用的時(shí)候?qū)⑺麄儌鬟f進(jìn)來,就可以通過共享大幅度第減少單個(gè)實(shí)例 的數(shù)目。

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

      享元與數(shù)據(jù)層

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

      說白點(diǎn),就是先捏一個(gè)的原始模型,然后隨著不同場合和環(huán)境,再產(chǎn)生各具特征的具體模型,很顯然,在這里需要產(chǎn)生不同的新對象,所以Flyweight模式中常出現(xiàn)Factory模式,F(xiàn)lyweight的內(nèi)部狀態(tài)是用來共享的,F(xiàn)lyweight factory負(fù)責(zé)維護(hù)一個(gè)Flyweight pool(模式池)來存放內(nèi)部狀態(tài)的對象。

      使用享元模式

      讓我們來演示一下如果通過一個(gè)類庫讓系統(tǒng)來管理所有的書籍,每個(gè)書籍的元數(shù)據(jù)暫定為如下內(nèi)容:

      ID
      Title
      Author
      Genre
      Page count
      Publisher ID
      ISBN

      我們還需要定義每本書被借出去的時(shí)間和借書人,以及退書日期和是否可用狀態(tài):

      checkoutDate
      checkoutMember
      dueReturnDate
      availability

      因?yàn)閎ook對象設(shè)置成如下代碼,注意該代碼還未被優(yōu)化:

      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方法在這里就不顯示了*/

      // 更新借出狀態(tài)
      updateCheckoutStatus: function(bookID, newStatus, checkoutDate,checkoutMember, newReturnDate){
      this.id = bookID;
      this.availability = newStatus;
      this.checkoutDate = checkoutDate;
      this.checkoutMember = checkoutMember;
      this.dueReturnDate = newReturnDate;
      },
      //續(xù)借
      extendCheckoutPeriod: function(bookID, newReturnDate){
      this.id = bookID;
      this.dueReturnDate = newReturnDate;
      },
      //是否到期
      isPastDue: function(bookID){
      var currentDate = new Date();
      return currentDate.getTime() > Date.parse(this.dueReturnDate);
      }
      };

      程序剛開始可能沒問題,但是隨著時(shí)間的增加,圖書可能大批量增加,并且每種圖書都有不同的版本和數(shù)量,你將會(huì)發(fā)現(xiàn)系統(tǒng)變得越來越慢。幾千個(gè)book對象在內(nèi)存里可想而知,我們需要用享元模式來優(yōu)化。

      我們可以將數(shù)據(jù)分成內(nèi)部和外部兩種數(shù)據(jù),和book對象相關(guān)的數(shù)據(jù)(title, author 等)可以歸結(jié)為內(nèi)部屬性,而(checkoutMember, dueReturnDate等)可以歸結(jié)為外部屬性。這樣,如下代碼就可以在同一本書里共享同一個(gè)對象了,因?yàn)椴还苷l借的書,只要書是同一本書,基本信息是一樣的:

      /*享元模式優(yōu)化代碼*/
      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;
      };

      定義基本工廠

      讓我們來定義一個(gè)基本工廠,用來檢查之前是否創(chuàng)建該book的對象,如果有就返回,沒有就重新創(chuàng)建并存儲(chǔ)以便后面可以繼續(xù)訪問,這確保我們?yōu)槊恳环N書只創(chuàng)建一個(gè)對象:

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

      管理外部狀態(tài)

      外部狀態(tài),相對就簡單了,除了我們封裝好的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);
      }
      };
      });

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

      享元模式與DOM

      關(guān)于DOM的事件冒泡,在這里就不多說了,相信大家都已經(jīng)知道了,我們舉兩個(gè)例子。

      例1:事件集中管理

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

      在這里我們結(jié)合一下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&amp;address=london%2C%20england&amp;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);
      // 判斷是哪一個(gè)子元素
      if(target.is("div.toggle")){
      self.handleClick(target);
      }
      });
      },

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

      例2:應(yīng)用享元模式提升性能

      另外一個(gè)例子,依然和jQuery有關(guān),一般我們在事件的回調(diào)函數(shù)里使用元素對象是會(huì)后,經(jīng)常會(huì)用到$(this)這種形式,其實(shí)它重復(fù)創(chuàng)建了新對象,因?yàn)楸旧砘卣{(diào)函數(shù)里的this已經(jīng)是DOM元素自身了,我們必要必要使用如下這樣的代碼:

       

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

      其實(shí),如果非要用$(this)這樣的形式,我們也可以實(shí)現(xiàn)自己版本的單實(shí)例模式,比如我們來實(shí)現(xiàn)一個(gè)jQuery.signle(this)這樣的函數(shù)以便返回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元素自身了,而且不進(jìn)行jQuery對象的創(chuàng)建。

      總結(jié)

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

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

      參考地址:http://www.addyosmani.com/resources/essentialjsdesignpatterns/book/#detailflyweight

      同步與推薦

      本文已同步至目錄索引:深入理解JavaScript系列

      深入理解JavaScript系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載等各類型的文章,如果對你有用,請推薦支持一把,給大叔寫作的動(dòng)力。

      主站蜘蛛池模板: 唐海县| 亚洲春色在线视频| 亚洲午夜精品国产电影在线观看| 色狠狠色噜噜AV一区| 国产女人看国产在线女人| 国产精品青青在线观看爽香蕉| 紫金县| 免费黄色大全一区二区三区| 黄页网站在线观看免费视频| 尼勒克县| 激情啪啪啪一区二区三区| 亚洲中文久久久精品无码| 惠来县| 亚洲无码在线免费观看| 久久久久久综合网天天| 人妻人人澡人人添人人爽人人玩| 亚洲国产免费图区在线视频| 国产好大好硬好爽免费不卡| 怡红院一区二区三区在线| 一区二区三区成人| 69精品丰满人妻无码视频a片| 色婷婷日日躁夜夜躁| 午夜成人无码免费看网站| 色偷偷www.8888在线观看| 国产一区二区黄色激情片| 亚洲性日韩精品一区二区| 又大又粗又爽的少妇免费视频| 久久精品国产福利一区二区| 日韩av片无码一区二区不卡| 国产成人亚洲老熟女精品| 影音先锋大黄瓜视频| 国产肥妇一区二区熟女精品| 欧美成本人视频免费播放| 99久久婷婷国产综合精品青草漫画 | 国产精品成人久久电影| 人妻系列无码专区无码中出| 久久亚洲人成网站| 亚洲综合网中文字幕在线| 97在线视频人妻无码| 成人精品区| 狠狠亚洲色一日本高清色|