您的位置:首页 > Web前端 > JavaScript

javascript设计模式之单例(singleton)模式

2015-08-16 11:02 751 查看
singleton模式限制了类的实例化次数只能有一次。singleton模式,该实例不存在的情况下,可以通过一个方法创建一个类来实现创建类的新实例;如果实例已经存在,它会简单的返回对象的引用。Singleton不同于静态类,它可以延迟实例化。



1.对象字面量实现

在javascript中实现单例模式有很多方式,其中最简单的就是对象字面量。

var Singleton={
     name:"vuturn",
     showName:function(){
          console.log(this.name);
         }
  }

当然也可以扩展该对象,可以添加私有成员和方法,使用闭包在其内部封装变量和方法。通过返回一个对象,暴露公有的方法和变量。

2.利用闭包实现

var mySingleton=(function(){
        var instance;
        function init(){
            function privateMethod(){
                console.log("This is private");
            }
            var privateVariable="This is privart too!";
            return {
             publicMethod:function(){
                 console.log("This is public!");
             },
                publicProperty:"This is public too!"
            }
        }
        return {
            getInstance: function () {
                if(!instance){
                    instance=init();
                }
                return instance;
            }
        }
    })();



3.使用new 操作符

我们要实现以下效果:

var uni=new Universe(),
    uni2=new Universe();
uni==uni2;


uni对象在第一次调用构造函数时创建,在第二次(或者更多次)时,直接返回同一个uni对象。这就是为什么uni===uni2,因为指向同一个对象的引用。

那么如何在javascript中实现这种模式呢?

需要Universe对象缓存this对象,以便第二次调用的时候 能够创建并返回同一个对象。有多种方式实现这一目标。

(1)可以使用全局变量来存储该实例。但是并不推荐这种做法,因为全局变量容易被覆盖。

(2)可以在构造函数的静态属性中缓存该实例。这种简洁做法的唯一缺点在于静态属性是公开访问的属性,外部代码可以修改。

(3)可以将该实例包装在闭包中。这样可以保证实例的私有性并且保证实例不会被构造函数之外的代码修改。

这里展示第二和第三种实现方式:

静态属性中的实例

function  Universe(){
      if(typeof Universe.instance ==="object"){
          return Universe.instance;
      }
      this.start_time=0;

      Universe.instance=this;

      return this;
  }

    var uni=new Universe();
    var uni2=new Universe();

  console.log(  uni===uni2 );


闭包中的实例

function  Universe(){
     var instance=this;

      this.start_time=0;

      Universe= function () {
          return instance;
      }
  }
    var uni=new Universe();
    var uni2=new Universe();

  console.log(  uni===uni2 );


上面的代码在第一次调用时,返回this指针,这时的构造函数已经被重写,以后再调用时,直接返回instance。这种模式的缺点在于重写了构造函数,会丢失所有在初始定义和重定义时刻之间添加到它里面的属性。在这里的特定的情况下,任何添加到Universe的原型中的对象都不会存在指向友原始实现所创建的活动链接。
看看下面的测试:

Universe.prototype.nothing=true;

    var uni=new Universe();

    Universe,prototype.everything=true;

    var uni2=new Universe();

    uni.nothing;  //true
    uni2.nothing;  //true

    uni.everything; //undefined
    uni2.everything; //undefined

    uni.constructor.name;  //Universe

    uni.constructor===Universe;  //false


之所以uni.constructor不再与Universe()构造函数相同,是因为uni.constructor仍然指向原始的构造函数。

如果需要原型和构造函数指针按照预期的那样运行,那么可以通过如下的方式实现:

function  Universe(){
     var instance;

      Universe= function () {
          return instance;
      }
      //重写原型
      Universe.prototype=this;

      instance=new Universe();
      instance.constructor=Universe;
      instance.start_time=0;

      return instance;
  }
   Universe.prototype.nothing=true;
    var uni=new Universe();
    Universe.prototype.everything=true;
    var uni2=new Universe();

    console.log(uni===uni2);
    console.log(uni);
    console.log(uni2);
    console.log(uni.constructor);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: