资讯专栏INFORMATION COLUMN

[译]Javascript中的单例模式

godlong_X / 1950人阅读

摘要:原文单例模式被熟知是因为它把一个类的实例化限制在只有一个对象。这在中也是可以实现的。单例和静态对象都很有用,但是不能过度使用。实践中,当我们在整个系统中只需要一个对象与其他对象通信的时候,单例模式是非常有用的。

原文:The Single Pattern

单例模式被熟知是因为它把一个类的实例化限制在只有一个对象。传统的实现方式是:创建一个类,这个类里面有一个方法在对象不存在的时候创造一个实例,存在的时候,只需要返回这个对象的引用即可。

单例和静态类(或者对象)是有区别的,因为我们可以延迟他们的初始化。因为他们需要一些在初始化的时候不能获得的信息。他们没有提供一种方式让不知道他们之前引用的代码去获取他们。这是因为由单例返回的既不是对象也不是类,而是一种结构。想想大括号形成的不是真正的闭包,函数作用于提供的闭包才是真正的闭包。

Javascript中,单例作为共享资源的命名空间,它隔离了实现的代码和全局变量,为了能够让函数有唯一的一个入口。

我们可以通过下面的方法实现单例:

    var mySingleton=(function(){
        //存储单例引用的实例
        var instance;

        function init(){
            //单例

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

            var privateVariable="Im alse 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 {

            //如果存在获取单例实例的引用
            //不存在,创建实例
            getInstance:function(){
                if(!instance){
                    instance=init();
                }
                return instance;
            }
        };
        
    })();

    var myBadSingleton=(function(){
        //指向单例的引用
        var instance;

        function init(){
            //单例
            var privateRandomNumber=Math.random();

            return {
                getRandomNumber:function(){
                    return privateRandomNumber;
                }
            }
        }

        return {
            //无论什么时候都创建一个单例实例
            getInstance:function(){
                instance=init();
    
                return instance;
            }
        };
    })();

    //使用:
    
    var singleA=mySingleton.getInstance();
    var singleB=mySingleton.getInstance();
    console.log(singA.getRandomNumber()===singleB.getRandomNumber()); //true

    var badSingleA=myBadSingleton.getInstance();
    var badSingleB=myBadSingleton.getInstance();
    console.log(badSingleA.getRandomNumber()!==badSingleB.getRandomNumber());//true
    
    //注意:因为我们使用的是随机数
    //所以上面的值还是有可能相同的
    //但是可能性很低,上面的例子还是有效的。

使用单例可以让我们有一个指向实例的统一入口(一般通过MySingleton.getInstance()的方式),这样我们就不需要直接通过new MySingleton()的方式直接调用啦。这在javascript中也是可以实现的。

在四人帮这本书中,单例的适用场景被描述为下面这些:

必须只有一个类的实例,而且必须可以通过大家都知道的入口让大家可以访问到。

当这个唯一的实例需要被之类扩展的时候,用户可以在不需要修改代码的情况下扩展它。

第二点指出了我们可能遇到的场景,比如:

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

这里,getInstance变得有些像工厂方法,我们访问它的时候并不需要更新我们的每一部分代码。上面的FooSingleton可能是BasicSingleton的之类,并且实现了同样的接口。

为什么在单例中延迟执行被认为很重要呢?:

在C++中,它被用来让我们解决动态初始化执行顺序的不可预测性,把控制权交给了程序。

需要注意的是区分类的静态实例和单例的区别是很重要的。尽管单例可以被实现成静态实例。但是同时也可以延迟构造,不需要消耗资源也不会消耗内存直到需要它的时候再初始化。

如果我们有一个可以被直接初始化的静态对象,我们需要确保代码是按照顺序执行的。(比如,车的对象初始化的时候车轮必须已经存在)并且它在你有很多资源文件的时候不会变大。

单例和静态对象都很有用,但是不能过度使用。就像不能过度使用其他模式一样。

实践中,当我们在整个系统中只需要一个对象与其他对象通信的时候,单例模式是非常有用的。下面就是单例在上下文中使用模式的一个例子:

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 );

尽管单例在这里使用时有效的,但是经常当我们需要在javascript中使用它的时候,往往意味着我们应该重新审视我们的设计啦。

他们往往意味着系统的模块要不就是耦合过紧啦,要么逻辑延伸的太大啦。单例的使用往往会让测试变得更加困难,因为存在隐藏依赖,难以创建多个实例,难以找到根依赖等问题。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86156.html

相关文章

  • 】我最喜欢的 JavaScript 设计模式

    摘要:原文链接译文原链译我最喜欢的设计模式我最喜欢的设计模式我觉得聊一下我爱用的设计模式应该很有意思。我是一步一步才定下来的,经过一段时间从各种来源吸收和适应直到达到一个能提供我所需的灵活性的模式。 原文链接:My Favorite JavaScript Design Pattern译文原链:【译】我最喜欢的 JavaScript 设计模式 我最喜欢的 JavaScript 设计模式 我觉得...

    xuxueli 评论0 收藏0
  • JavaScript设计模式----单例模式

    摘要:不符合设计模式中的单一职责的概念。引入代理实现单例模式引入代理实现单例模式的特点我们负责管理单例的逻辑移到了代理类中。的单例模式对比在以上的代码中实现的单例模式都混入了传统面向对象语言的特点。 声明:这个系列为阅读《JavaScript设计模式与开发实践》 ----曾探@著一书的读书笔记 1.单例模式的特点和定义 保证一个类仅有一个实例,并且提供一个访问它的全局访问点。 2.传统面向对...

    selfimpr 评论0 收藏0
  • JavaScript设计模式与开发实践 | 04 - 单例模式

    摘要:观察构造函数的代码,该构造函数实际上负责了两件事情第一是创建对象和执行初始化方法,第二是保证只有一个对象。惰性单例在实际开发中非常有用,是单例模式的重点。 单例模式 单例模式的定义是: 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器的window对象等。例如,当我们点击登录按钮时,页面会弹出一...

    awkj 评论0 收藏0
  • JavaScript设计模式与开发实践系列之单例模式

    摘要:本系列为设计模式与开发实践作者曾探学习总结,如想深入了解,请支持作者原版单例模式实现单例模式单例模式的定义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。 本系列为《JavaScript设计模式与开发实践》(作者:曾探)学习总结,如想深入了解,请支持作者原版 单例模式 实现单例模式 单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式是一种常用的模式...

    Airy 评论0 收藏0
  • JavaScript设计模式单例模式

    摘要:原文博客地址单例模式系统中被唯一使用,一个类只有一个实例。中的单例模式利用闭包实现了私有变量两者是否相等弱类型,没有私有方法,使用者还是可以直接一个,也会有方法分割线不是单例最简单的单例模式,就是对象。 原文博客地址:https://finget.github.io/2018/11/06/single/ 单例模式 系统中被唯一使用,一个类只有一个实例。实现方法一般是先判断实例是否存在,...

    lk20150415 评论0 收藏0

发表评论

0条评论

godlong_X

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<