JavaScript设计模式之单例模式

June 15, 2015

801

Singleton(单例)模式限制了类的实例化次数只能一次,以前使用PHP的时候,常用单例模式来处理数据库连接,保证数据库句柄唯一。

Singleton模式,在实例不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例;如果实例已经存在,它会简单返回该对象的引用。

今天,采用JavaScript来实现单例模式。在JavaScript中,有多种方式可以实现单例模式。

1、使用对象字面值

代码如下:

var obj = {
  name: 'wen'
};

在JavaScript中,对象之间永远不会完全相等,因此,可以认为在使用对象字面量创建对象的时候,就是创建一个单例。

2、重写构造函数

代码如下:

function Singleton() {
  //缓存实例
  var instance;

  //重写构造函数
  Singleton = function() {
    return instance;
  };

  //保留原型
  Singleton.prototype = this;

  //实例
  instance = new Singleton();

  //构造函数指针
  instance.constructor = Singleton;

  return instance;
}

在这里,第一次实例化采用instance保存了Singleton的实例,通过重写构造函数保证了再次实例化时返回instance,保证了唯一性。

3、将构造函数和实例封装在闭包中

代码如下:

var Singleton;

(function() {
  var instance;

  Singleton = function() {
    if (instance !== undefined) {
      return instance;
    }

    instance = this;
  };
}());

在第一次调用构造函数时,会创建一个对象,并且使得私有instance指向该对象,从第二次调用之后,该构造函数仅返回该私有变量。

当Singleton可以作为一个静态的实例实现时,它可以延时构建,直到需要使用静态实例之前,无需使用资源或内存。类似于PHP中getInstance返回一个实例,我们也采用getInstance来返回实例。代码如下:

var Singleton = (function () {
    var _instance;
    function init() {
        /*单例代码*/
        return {
            user: 'Wen',
            hi: function() {
                console.log('My name is ' + this.user);
            }
        };
    }

    return {
        getInstance: function () {
            if (!_instance) {
                _instance = init();
            }
            return _instance;
        }
    };
})();

采用如下方式调用:

Singleton.getInstance().hi();

接下来,实现一个单例通用化处理,将一个类转化成一个单例,并且采用自调用构造函数,使采用new方式或者非new方式调用保持一致,代码如下:

function singletonize(fn) {
  //缓存实例
  var instance;

  //检查输入
  if (Object.prototype.toString.call(fn) !== '[object Function]') {
    throw new TypeError('fn should be a function');
  }

  //单例
  function Singleton() {
    if (instance === undefined) { 
      var self = this instanceof Singleton ? this : Object.create(Singleton.prototype);
      instance = self;
      fn.apply(instance, arguments);//第一次初始化时调用原函数fn构造函数
    }
  
    return instance;
  }

  //继承
  Singleton.prototype = fn.prototype;

  return Singleton;
}

在通用化函数中,创建一个单例,在单例构造函数中,采用自调用,同时将参数传入fn构造函数中,并将单例的原型指向函数fn的原型,最终返回单例。采用如下方式调用:

function Test(user) {
  this.username = user || 'wenwei';
}

var Test1 = singletonize(Test);
var test1 = Test1('wen'), test2 = new Test1();
console.log(test1 === test2); //true

设计模式 」相关文章

Wen's Blog

文章归档 » 文章标签 » 博主:吴文伟,Web开发爱好者,专注于前端开发,该博客用于记录和分享平时遇到的一些问题以及知识。

订阅

联系方式

链接