欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript編程的單例設(shè)計(jì)模講解

 更新時(shí)間:2015年11月10日 14:18:19   投稿:goldensun  
這篇文章主要介紹了JavaScript編程的單例設(shè)計(jì)模講解,單例模式編寫有利于JS代碼的維護(hù)和調(diào)試,需要的朋友可以參考下

在Javascript中,單例模式是一種最基本又經(jīng)常用到的設(shè)計(jì)模式,可能在不經(jīng)意間就用到了單例模式。
本文將從最基礎(chǔ)的理論開始,講述單例模式的基本概念和實(shí)現(xiàn),最后用一個(gè)例子來講述單例模式的應(yīng)用。

理論基礎(chǔ)

概念

單例模式,顧名思義就是只有一個(gè)實(shí)例存在。通過單例模式可以保證系統(tǒng)中一個(gè)類只有一個(gè)實(shí)例而且該實(shí)例易于外界訪問,從而方便對(duì)實(shí)例個(gè)數(shù)的控制并節(jié)約系統(tǒng)資源。如果希望在系統(tǒng)中某個(gè)類的對(duì)象只能存在一個(gè),單例模式是最好的解決方案。

基本結(jié)構(gòu)

最簡單的單例模式起始就是一個(gè)對(duì)象字面量,它將有關(guān)聯(lián)的屬性和方法組織到一起。

var singleton = {
  prop:"value",
  method:function(){
  }
}

這種形式的單例模式,所有成員都是公開的,都可以通過singleton來訪問。這樣的缺點(diǎn)是單例中有一些輔助的方法并不希望暴露給使用者,如果使用者用了這些方法,然后在后面維護(hù)的時(shí)候,一些輔助方法被刪除,這樣會(huì)造成程序錯(cuò)誤。
如何避免這樣從的錯(cuò)誤呢?

包含私有成員的單例模式

要怎么在類中創(chuàng)建私有成員呢,這通過需要閉包來進(jìn)行實(shí)現(xiàn),關(guān)于閉包的知識(shí),本文不再贅述,大家可以自行Google。
基本形式如下:

var singleton = (function () {
      var privateVar = "private";
      return {
        prop: "value",
        method: function () {
          console.log(privateVar);
        }
      }
    })();

首先是一個(gè)自執(zhí)行的匿名函數(shù),在匿名函數(shù)中,聲明了一個(gè)變量privateVar,返回一個(gè)對(duì)象賦值給單例對(duì)象singleton。在匿名函數(shù)外部無法訪問到privateVar變量,它就是單例對(duì)象的私有變量,只能在函數(shù)內(nèi)部或通過暴露出來的方法去訪問這個(gè)私有變量。這種形式又被成為模塊模式。

惰性實(shí)例化

不管是直接字面量或者私有成員的單例模式,兩者都是在腳本加載時(shí)就被創(chuàng)建出來的單例,但是有時(shí)候,頁面可能永遠(yuǎn)也用不到這個(gè)單例對(duì)象,這樣會(huì)造成資源浪費(fèi)。對(duì)于這種情況,最佳的處理方式就是惰性加載,就是說在需要的時(shí)候才去真正實(shí)例化這個(gè)單例對(duì)象,如何實(shí)現(xiàn)呢?

var singleton = (function () {
      function init() {
        var privateVar = "private";
        return {
          prop: "value",
          method: function () {
            console.log(privateVar);
          }
        }
      }
      var instance = null;
      return {
        getInstance: function () {
          if (!instance) {
            instance = init();
          }
          return instance;
        }
      }
    })();

首先將創(chuàng)建單例對(duì)象的代碼封裝到init函數(shù)中,然后聲明一個(gè)私有變量instance表示單例對(duì)象的實(shí)例,公開一個(gè)方法getInstance來獲取單例對(duì)象。
調(diào)用的時(shí)候就通過singleton.getInstance()來進(jìn)行調(diào)用,單例對(duì)象是在調(diào)用getInstance的時(shí)候才真正被創(chuàng)建。

適用場(chǎng)合

單例模式是JS中最常使用的設(shè)計(jì)模式,從增強(qiáng)模塊性和代碼組織性等方面來說,應(yīng)該盡可能的使用單例模式。它可以把相關(guān)代碼組織到一起便于維護(hù),對(duì)于大型項(xiàng)目,每個(gè)模塊惰性加載可以提高性能,隱藏實(shí)現(xiàn)細(xì)節(jié),暴露出常用的api。常見的類庫比如underscore,jQuery我們都可以將其理解為單例模式的應(yīng)用。

結(jié)合實(shí)戰(zhàn)

前面已經(jīng)講過,單例模式是最常用的設(shè)計(jì)模式之一,我們來舉個(gè)例子進(jìn)行說明,
下面的代碼主要實(shí)現(xiàn)一個(gè)簡單的日期幫助類,通過單例模式實(shí)現(xiàn):

基本的單例模式結(jié)構(gòu)

var dateTimeHelper = {
      now: function () {
        return new Date();
      },
      format: function (date) {
        return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
      }
    }; 
console.log(dateTimeHelper.now());

這段代碼通過對(duì)象字面量實(shí)現(xiàn)單例模式,使用的時(shí)候直接調(diào)用方法即可。

惰性加載實(shí)現(xiàn)單例模式

 var dateTimeHelper = (function () {
      function init() {
        return {
          now: function () {
            return new Date();
          },
          format: function (date) {
            return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
          }
        }
      }
      var instance = null;
      return {
        getInstance: function () {
          if (!instance) {
            instance = init();
          }
          return instance;
        }
      }
    })(); 
console.log(dateTimeHelper.getInstance().now())

這就是惰性加載的單例模式。

下面再來看幾個(gè)實(shí)例:
實(shí)現(xiàn)1: 最簡單的對(duì)象字面量

var singleton = {

    attr : 1,

    method : function(){ return this.attr; }

  }



var t1 = singleton ;

var t2 = singleton ;

    那么很顯然的, t1 === t2 。

    十分簡單,并且非常使用,不足之處在于沒有什么封裝性,所有的屬性方法都是暴露的。對(duì)于一些需要使用私有變量的情況就顯得心有余而力不足了。當(dāng)然在對(duì)于 this 的問題上也是有一定弊端的。

    實(shí)現(xiàn)2:構(gòu)造函數(shù)內(nèi)部判斷

    其實(shí)和最初的JS實(shí)現(xiàn)有點(diǎn)類似,不過是將對(duì)是否已經(jīng)存在該類的實(shí)例的判斷放入構(gòu)造函數(shù)內(nèi)部。

function Construct(){

  // 確保只有單例

  if( Construct.unique !== undefined ){

    return Construct.unique; 

  }

  // 其他代碼

  this.name = "NYF";

  this.age="24";

  Construct.unique = this;

}



var t1 = new Construct() ;

var t2 = new Construct() ;

    那么也有的, t1 === t2 。

    也是非常簡單,無非就是提出一個(gè)屬性來做判斷,但是該方式也沒有安全性,一旦我在外部修改了Construct的unique屬性,那么單例模式也就被破壞了。 

    實(shí)現(xiàn)3 : 閉包方式   

    對(duì)于大著 靈活 牌子的JS來說,任何問題都能找到 n 種答案,只不過讓我自己去掂量孰優(yōu)孰劣而已,下面就簡單的舉幾個(gè)使用閉包實(shí)現(xiàn)單例模式的方法,無非也就是將創(chuàng)建了的單例緩存而已。

var single = (function(){

  var unique;

  function Construct(){

    // ... 生成單例的構(gòu)造函數(shù)的代碼

  }



  unique = new Constuct();



  return unique;

})();

    只要 每次講 var t1 = single; var t2 = single;即可。 與對(duì)象字面量方式類似。不過相對(duì)而言更安全一點(diǎn),當(dāng)然也不是絕對(duì)安全。

    如果希望會(huì)用調(diào)用 single() 方式來使用,那么也只需要將內(nèi)部的 return 改為

  return function(){

    return unique;

  } 

    以上方式也可以使用 new 的方式來進(jìn)行(形式主義的趕腳)。當(dāng)然這邊只是給了閉包的一種例子而已,也可以在 Construct 中判斷單例是否存在 等等。 各種方式在各個(gè)不同情況做好選著即可。


總結(jié)

單例模式的好處在于對(duì)代碼的組織作用,將相關(guān)的屬性和方法封裝在一個(gè)不會(huì)被多次實(shí)例化的對(duì)象中,讓代碼的維護(hù)和調(diào)試更加輕松。隱藏了實(shí)現(xiàn)細(xì)節(jié),可以防止被錯(cuò)誤修改,還防止了全局命名空間的污染。另外可以通過惰性加載提高性能,減少不必要的內(nèi)存消耗。

相關(guān)文章

最新評(píng)論