在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 單例模式
中介者模式
MVVM
亨元模式
設(shè)計(jì)模式分類概覽表
ES Harmony
組合模式
CommonJS
jQuery 插件的設(shè)計(jì)模式
外觀模式
觀察者模式
建造者模式
構(gòu)造器模式
外觀模式
簡(jiǎn)介
AMD
原型模式
設(shè)計(jì)模式的分類
觀察者模式
命名空間模式
代理模式
編寫(xiě)設(shè)計(jì)模式
適配器模式
反模式
什么是設(shè)計(jì)模式
模塊化模式
MVC
Mixin 模式
裝飾模式
設(shè)計(jì)模式的結(jié)構(gòu)
單例模式
迭代器模式
命令模式
工廠模式
MVP
暴露模塊模式
惰性初始模式

單例模式

單例模式之所以這么叫,是因?yàn)樗拗埔粋€(gè)類只能有一個(gè)實(shí)例化對(duì)象。經(jīng)典的實(shí)現(xiàn)方式是,創(chuàng)建一個(gè)類,這個(gè)類包含一個(gè)方法,這個(gè)方法在沒(méi)有對(duì)象存在的情況下,將會(huì)創(chuàng)建一個(gè)新的實(shí)例對(duì)象。如果對(duì)象存在,這個(gè)方法只是返回這個(gè)對(duì)象的引用。

單例和靜態(tài)類不同,因?yàn)槲覀兛梢酝顺鰡卫某跏蓟瘯r(shí)間。通常這樣做是因?yàn)?,在初始化的時(shí)候需要一些額外的信息,而這些信息在聲明的時(shí)候無(wú)法得知。對(duì)于并不知曉對(duì)單例模式引用的代碼來(lái)講,單例模式?jīng)]有為它們提供一種方式可以簡(jiǎn)單的獲取單例模式。這是因?yàn)?,單例模式既不返回?duì)象也不返回類,它只返回一種結(jié)構(gòu)??梢灶惐乳]包中的變量不是閉包-提供閉包的函數(shù)域是閉包(繞進(jìn)去了)。

在JavaScript語(yǔ)言中, 單例服務(wù)作為一個(gè)從全局空間的代碼實(shí)現(xiàn)中隔離出來(lái)共享的資源空間是為了提供一個(gè)單獨(dú)的函數(shù)訪問(wèn)指針。

我們能像這樣實(shí)現(xiàn)一個(gè)單例:

var mySingleton = (function () {

  // Instance stores a reference to the Singleton
  var instance;

  function init() {

    // 單例

    // 私有方法和變量
    function privateMethod(){
        console.log( "I am private" );
    }

    var privateVariable = "Im also private";

    var privateRandomNumber = Math.random();

    return {

      // 共有方法和變量
      publicMethod: function () {
        console.log( "The public can see me!" );
      },

      publicProperty: "I am also public",

      getRandomNumber: function() {
        return privateRandomNumber;
      }

    };

  };

  return {

    // 如果存在獲取此單例實(shí)例,如果不存在創(chuàng)建一個(gè)單例實(shí)例
    getInstance: function () {

      if ( !instance ) {
        instance = init();
      }

      return instance;
    }

  };

})();

var myBadSingleton = (function () {

  // 存儲(chǔ)單例實(shí)例的引用
  var instance;

  function init() {

    // 單例

    var privateRandomNumber = Math.random();

    return {

      getRandomNumber: function() {
        return privateRandomNumber;
      }

    };

  };

  return {

    // 總是創(chuàng)建一個(gè)新的實(shí)例
    getInstance: function () {

      instance = init();

      return instance;
    }

  };

})();

// 使用:

var singleA = mySingleton.getInstance();
var singleB = mySingleton.getInstance();
console.log( singleA.getRandomNumber() === singleB.getRandomNumber() ); // true

var badSingleA = myBadSingleton.getInstance();
var badSingleB = myBadSingleton.getInstance();
console.log( badSingleA.getRandomNumber() !== badSingleB.getRandomNumber() ); // true

創(chuàng)建一個(gè)全局訪問(wèn)的單例實(shí)例 (通常通過(guò) MySingleton.getInstance()) 因?yàn)槲覀儾荒?至少在靜態(tài)語(yǔ)言中) 直接調(diào)用 new MySingleton() 創(chuàng)建實(shí)例. 這在JavaScript語(yǔ)言中是不可能的。

在四人幫(GoF)的書(shū)里面,單例模式的應(yīng)用描述如下:

  • 每個(gè)類只有一個(gè)實(shí)例,這個(gè)實(shí)例必須通過(guò)一個(gè)廣為人知的接口,來(lái)被客戶訪問(wèn)。
  • 子類如果要擴(kuò)展這個(gè)唯一的實(shí)例,客戶可以不用修改代碼就能使用這個(gè)擴(kuò)展后的實(shí)例。

關(guān)于第二點(diǎn),可以參考如下的實(shí)例,我們需要這樣編碼:

mySingleton.getInstance = function(){
  if ( this._instance == null ) {
    if ( isFoo() ) {
       this._instance = new FooSingleton();
    } else {
       this._instance = new BasicSingleton();
    }
  }
  return this._instance;
};

在這里,getInstance 有點(diǎn)類似于工廠方法,我們不需要去更新每個(gè)訪問(wèn)單例的代碼。FooSingleton可以是BasicSinglton的子類,并且實(shí)現(xiàn)了相同的接口。

為什么對(duì)于單例模式來(lái)講,延遲執(zhí)行執(zhí)行這么重要?

在c++代碼中,單例模式將不可預(yù)知的動(dòng)態(tài)初始化順序問(wèn)題隔離掉,將控制權(quán)返回給程序員。

區(qū)分類的靜態(tài)實(shí)例和單例模式很重要:盡管單例模式可以被實(shí)現(xiàn)成一個(gè)靜態(tài)實(shí)例,但是單例可以懶構(gòu)造,在真正用到之前,單例模式不需要分配資源或者內(nèi)存。

如果我們有個(gè)靜態(tài)對(duì)象可以被直接初始化,我們需要保證代碼總是以同樣的順序執(zhí)行(例如 汽車(chē)需要輪胎先初始化)當(dāng)你有很多源文件的時(shí)候,這種方式?jīng)]有可擴(kuò)展性。

單例模式和靜態(tài)對(duì)象都很有用,但是不能濫用-同樣的我們也不能濫用其它模式。

在實(shí)踐中,當(dāng)一個(gè)對(duì)象需要和另外的對(duì)象進(jìn)行跨系統(tǒng)協(xié)作的時(shí)候,單例模式很有用。下面是一個(gè)單例模式在這種情況下使用的例子:

var SingletonTester = (function () {

  // options: an object containing configuration options for the singleton
  // e.g var options = { name: "test", pointX: 5}; 
  function Singleton( options )  {

    // set options to the options supplied
    // or an empty object if none are provided
    options = options || {};

    // set some properties for our singleton
    this.name = "SingletonTester";

    this.pointX = options.pointX || 6;

    this.pointY = options.pointY || 10; 

  }

  // our instance holder 
  var instance;

  // an emulation of static variables and methods
  var _static  = {  

    name:  "SingletonTester",

    // Method for getting an instance. It returns
    // a singleton instance of a singleton object
    getInstance:  function( options ) {   
      if( instance  ===  undefined )  {    
        instance = new Singleton( options );   
      }   

      return  instance; 

    } 
  }; 

  return  _static;

})();

var singletonTest  =  SingletonTester.getInstance({
  pointX:  5
});

// Log the output of pointX just to verify it is correct
// Outputs: 5
console.log( singletonTest.pointX );

盡管單例模式有著合理的使用需求,但是通常當(dāng)我們發(fā)現(xiàn)自己需要在javascript使用它的時(shí)候,這是一種信號(hào),表明我們可能需要去重新評(píng)估自己的設(shè)計(jì)。

這通常表明系統(tǒng)中的模塊要么緊耦合要么邏輯過(guò)于分散在代碼庫(kù)的多個(gè)部分。單例模式更難測(cè)試,因?yàn)榭赡苡卸喾N多樣的問(wèn)題出現(xiàn),例如隱藏的依賴關(guān)系,很難去創(chuàng)建多個(gè)實(shí)例,很難清理依賴關(guān)系,等等。

要想進(jìn)一步了解關(guān)于單例的信息,可以讀讀 Miller Medeiros 推薦的這篇非常棒的關(guān)于單例模式以及單例模式各種各樣問(wèn)題的文章,也可以看看這篇文章的評(píng)論,這些評(píng)論討論了單例模式是怎樣增加了模塊間的緊耦合。我很樂(lè)意去支持這些推薦,因?yàn)檫@兩篇文章提出了很多關(guān)于單例模式重要的觀點(diǎn),而這些觀點(diǎn)是很值得重視的。

上一篇:原型模式下一篇:Mixin 模式