深入理解JavaScript系列(25):設計模式之單例模式詳解

字號:


    這篇文章主要介紹了深入理解JavaScript系列(25):設計模式之單例模式詳解,本文給出了多種單例模式的實現(xiàn)方式,需要的朋友可以參考下
    介紹
    從本章開始,我們會逐步介紹在JavaScript里使用的各種設計模式實現(xiàn),在這里我不會過多地介紹模式本身的理論,而只會關注實現(xiàn)。OK,正式開始。
    在傳統(tǒng)開發(fā)工程師眼里,單例就是保證一個類只有一個實例,實現(xiàn)的方法一般是先判斷實例存在與否,如果存在直接返回,如果不存在就創(chuàng)建了再返回,這就確保了一個類只有一個實例對象。在JavaScript里,單例作為一個命名空間提供者,從全局命名空間里提供一個唯一的訪問點來訪問該對象。
    正文
    在JavaScript里,實現(xiàn)單例的方式有很多種,其中最簡單的一個方式是使用對象字面量的方法,其字面量里可以包含大量的屬性和方法:
    代碼如下:
    var mySingleton = {
    property1: "something",
    property2: "something else",
    method1: function () {
    console.log('hello world');
    }
    };
    如果以后要擴展該對象,你可以添加自己的私有成員和方法,然后使用閉包在其內部封裝這些變量和函數(shù)聲明。只暴露你想暴露的public成員和方法,樣例代碼如下:
    代碼如下:
    var mySingleton = function () {
    /* 這里聲明私有變量和方法 */
    var privateVariable = 'something private';
    function showPrivate() {
    console.log(privateVariable);
    }
    /* 公有變量和方法(可以訪問私有變量和方法) */
    return {
    publicMethod: function () {
    showPrivate();
    },
    publicVar: 'the public can see this!'
    };
    };
    var single = mySingleton();
    single.publicMethod(); // 輸出 'something private'
    console.log(single.publicVar); // 輸出 'the public can see this!'
    上面的代碼很不錯了,但如果我們想做到只有在使用的時候才初始化,那該如何做呢?為了節(jié)約資源的目的,我們可以另外一個構造函數(shù)里來初始化這些代碼,如下:
    代碼如下:
    var Singleton = (function () {
    var instantiated;
    function init() {
    /*這里定義單例代碼*/
    return {
    publicMethod: function () {
    console.log('hello world');
    },
    publicProperty: 'test'
    };
    }
    return {
    getInstance: function () {
    if (!instantiated) {
    instantiated = init();
    }
    return instantiated;
    }
    };
    })();
    /*調用公有的方法來獲取實例:*/
    Singleton.getInstance().publicMethod();
    知道了單例如何實現(xiàn)了,但單例用在什么樣的場景比較好呢?其實單例一般是用在系統(tǒng)間各種模式的通信協(xié)調上,下面的代碼是一個單例的最佳實踐:
    代碼如下:
    var SingletonTester = (function () {
    //參數(shù):傳遞給單例的一個參數(shù)集合
    function Singleton(args) {
    //設置args變量為接收的參數(shù)或者為空(如果沒有提供的話)
    var args = args || {};
    //設置name參數(shù)
    this.name = 'SingletonTester';
    //設置pointX的值
    this.pointX = args.pointX || 6; //從接收的參數(shù)里獲取,或者設置為默認值
    //設置pointY的值
    this.pointY = args.pointY || 10;
    }
    //實例容器
    var instance;
    var _static = {
    name: 'SingletonTester',
    //獲取實例的方法
    //返回Singleton的實例
    getInstance: function (args) {
    if (instance === undefined) {
    instance = new Singleton(args);
    }
    return instance;
    }
    };
    return _static;
    })();
    var singletonTest = SingletonTester.getInstance({ pointX: 5 });
    console.log(singletonTest.pointX); // 輸出 5
    其它實現(xiàn)方式
    方法1:
    代碼如下:
    function Universe() {
    // 判斷是否存在實例
    if (typeof Universe.instance === 'object') {
    return Universe.instance;
    }
    // 其它內容
    this.start_time = 0;
    this.bang = "Big";
    // 緩存
    Universe.instance = this;
    // 隱式返回this
    }
    // 測試
    var uni = new Universe();
    var uni2 = new Universe();
    console.log(uni === uni2); // true
    方法2:
    代碼如下:
    function Universe() {
    // 緩存的實例
    var instance = this;
    // 其它內容
    this.start_time = 0;
    this.bang = "Big";
    // 重寫構造函數(shù)
    Universe = function () {
    return instance;
    };
    }
    // 測試
    var uni = new Universe();
    var uni2 = new Universe();
    uni.bang = "123";
    console.log(uni === uni2); // true
    console.log(uni2.bang); // 123
    方法3:
    代碼如下:
    function Universe() {
    // 緩存實例
    var instance;
    // 重新構造函數(shù)
    Universe = function Universe() {
    return instance;
    };
    // 后期處理原型屬性
    Universe.prototype = this;
    // 實例
    instance = new Universe();
    // 重設構造函數(shù)指針
    instance.constructor = Universe;
    // 其它功能
    instance.start_time = 0;
    instance.bang = "Big";
    return instance;
    }
    // 測試
    var uni = new Universe();
    var uni2 = new Universe();
    console.log(uni === uni2); // true
    // 添加原型屬性
    Universe.prototype.nothing = true;
    var uni = new Universe();
    Universe.prototype.everything = true;
    var uni2 = new Universe();
    console.log(uni.nothing); // true
    console.log(uni2.nothing); // true
    console.log(uni.everything); // true
    console.log(uni2.everything); // true
    console.log(uni.constructor === Universe); // true
    方式4:
    代碼如下:
    var Universe;
    (function () {
    var instance;
    Universe = function Universe() {
    if (instance) {
    return instance;
    }
    instance = this;
    // 其它內容
    this.start_time = 0;
    this.bang = "Big";
    };
    } ());
    //測試代碼
    var a = new Universe();
    var b = new Universe();
    alert(a === b); // true
    a.bang = "123";
    alert(b.bang); // 123