javascript设计模式交流(一) ——Singleton Pattern

转载 2012年03月27日 11:38:49


原文出处:http://bbs.51js.com/thread-43775-1-1.html


即使是简单的脚本语言,应用良好的模式可以得到非常“优美”的代码和较高的效率。
尤其是对于交互要求较高的B/S系统,非常有必要用设计模式来优化代码。

单件模式(Singleton Pattern)是一种非常基本和重要的创建型模式。
“单件”的职责是保证一个类有且只有一个实例,并提供一个访问它的全局访问点。
在程序设计过程中,有很多情况下需要确保一个类只能有一个实例。

传统的编程语言中为了使一个类只有一个实例,最容易的方法是在类中嵌入静态变量,并在第一个实例中设置该变量,而且每次进入构造函数都要做检查,不管类有多少个实例,静态变量只能有一个实例。为了防止类被多次初始化,要把构造函数声明为私有的,这样只能在静态方法里创建一个实例。

在javascript中,虽然我们仍然可以指定静态方法来构造对象,但由于我们不能利用构造函数的“私有”来禁止多个实例的生成,因此要完全实现Singleton并没有想象中那么简单。

请看下面的例子:

  1. <script>
  2. function SingletonObject()
  3. {
  4.         SingletonObject.prototype.methodA = function()
  5.         {
  6.                 alert('methodA');
  7.         }
  8.         SingletonObject.prototype.methodB = function()
  9.         {
  10.                 alert('methodB');
  11.         }
  12.         SingletonObject.instance = this;
  13. }
  14. SingletonFactory = new Object();
  15. SingletonFactory.getInstance = function()
  16. {
  17.         if(SingletonObject.instance == null)
  18.                 return new SingletonObject();
  19.         else
  20.                 return SingletonObject.instance;
  21. }

  22. var instA = SingletonFactory.getInstance();
  23. var instB = SingletonFactory.getInstance();
  24. instA.methodA();
  25. instB.methodA();
  26. alert(instA == instB); //成功
  27. var instC = new SingletonObject();
  28. instC.methodA();
  29. alert(instA == instC); //失败
  30. </script>
复制代码运行代码另存代码

上面的例子试图通过传统的方式来实现Singleton模式,而通过调用SingletonTest.getInstance()来获得对象确实可以保证“唯一实例”,然而,这个例子的失败之处在于它并没有有效地禁止Singleton对象的构造,因此如果我们在程序代码中人工加入new SingletonObject(),仍然可以获得到多个对象而导致模式失败。

一个改进的替代方案如下:
  1. <script>
  2. function SingletonObject()
  3. {
  4.         if(SingletonObject.instance != null)
  5.         {
  6.                 alert("不能创建多个singleton实例!");
  7.                 throw new Error();
  8.         }
  9.         SingletonObject.prototype.methodA = function()
  10.         {
  11.                 alert('methodA');
  12.         }
  13.         SingletonObject.prototype.methodB = function()
  14.         {
  15.                 alert('methodB');
  16.         }
  17.         SingletonObject.instance = this;
  18. }
  19. SingletonFactory = new Object();
  20. SingletonFactory.getInstance = function()
  21. {
  22.         if(SingletonObject.instance == null)
  23.                 return new SingletonObject();
  24.         else
  25.                 return SingletonObject.instance;
  26. }

  27. var instA = SingletonFactory.getInstance();
  28. var instB = SingletonFactory.getInstance();
  29. instA.methodA();
  30. instB.methodA();
  31. alert(instA == instB); //成功
  32. try
  33. {var instC = new SingletonObject(); }//抛出异常
  34. catch(e)
  35. {alert('系统成功抛出了异常,阻止了instC的构造!');}
  36. </script>
复制代码运行代码另存代码

这样当用户试图自己创建多个对象的时候,通过人工抛出异常来阻止。不过这么做还是有一点点违反了"初衷",即没有满足“必须通过静态方法来构造唯一实例”这个基本条件。因为用户可以在最开始的时候还是可以采用new操作符来构造对象,比如在一开始写var instA = new SingletonObject()来构造instA并不会导致抛出异常,这不能不说是这种方法的一个缺陷。

于是我们进一步思考,得到了下面第三种方法,这种方法巧妙利用了“匿名”函数的特征来禁止对SingletonObject类构造函数的访问,可以说比较好的模拟了私有构造函数的特性,从而比较完美地解决了用javascript实现Singleton Pattern的问题。

  1. <script>
  2. (function(){
  3.         //instance declared
  4.         //SingletonFactory Interface
  5.         SingletonFactory = {
  6.                 getInstance : getInstance
  7.         }

  8.         //private classes
  9.         function SingletonObject()
  10.         {
  11.                 SingletonObject.prototype.methodA = function()
  12.                 {
  13.                         alert('methodA');
  14.                 }
  15.                 SingletonObject.prototype.methodB = function()
  16.                 {
  17.                         alert('methodB');
  18.                 }
  19.                 SingletonObject.instance = this;
  20.         }
  21.         
  22.         //SingletonFactory implementions
  23.         function getInstance()
  24.         {
  25.                 if(SingletonObject.instance == null)
  26.                         return new SingletonObject();
  27.                         
  28.                 else
  29.                         return SingletonObject.instance;
  30.         }

  31. })();

  32. var instA = null;
  33. try
  34. {
  35. alert("试图通过new SingletonObject()构造实例!");
  36. instA = new SingletonObject();
  37. }
  38. catch(e){alert("SingletonObject构造函数不能从外部访问,系统抛出了异常!");}

  39. instA = SingletonFactory.getInstance();  //通过Factory上定义的静态方法获得
  40. var instB = SingletonFactory.getInstance();
  41. instA.methodA();
  42. instB.methodA();

  43. alert(instA == instB); //成功

  44. var instC = null;
  45. try
  46. {
  47. alert("试图通过new SingletonObject()构造实例!");
  48. instC = new SingletonObject();
  49. }
  50. catch(e){alert("SingletonObject构造函数不能从外部访问,系统抛出了异常!");}
  51. </script>
复制代码运行代码另存代码

设计模式(创建型)之单例模式(Singleton Pattern)

单例模式可能是23种设计模式中最简单的。应用也非常广泛,譬如Android中的数据库访问等操作都可以运用单例模式。核心概念: 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称...
  • yanbober
  • yanbober
  • 2015年04月27日 16:50
  • 2575

设计模式之---单例模式(Singleton Design Pattern)

场景 对象只要利用自己的属性完成了自己的任务.那该对象就是承担了责任。 除了维持了自身的一致性,该对象无需承担其他任何责任。 如果该对象还承担着其他责任,而其他对象又依赖于该特定对象所承担的贵任...
  • u010878994
  • u010878994
  • 2016年04月26日 01:19
  • 555

我所理解的设计模式(C++实现)——工厂方法模式(Factory Method Pattern)

工厂方法模式不同于简单工厂模式的地方在于工厂方法模式把对象的创建过程放到里子类里。这样工厂父对象和产品父对象一样,可以是抽象类或者接口,只定义相应的规范或操作,不涉及具体的创建或实现细节。  其...
  • tanningzhong
  • tanningzhong
  • 2015年01月24日 14:51
  • 584

设计模式-单例模式(Singleton)各种写法和分析比较

介绍单例模式是设计模式中比较简单容易理解的。它的出现主要是: 保证一个类仅有一个实例,并提供一个访问它的全局访问点 其实就在系统运行期间中保证只有这么一个实例,并能够全局访问。应用场景就是当需要一...
  • Card361401376
  • Card361401376
  • 2016年05月07日 23:51
  • 3808

C++设计模式5--单例模式Singleton--当前对象只有一个实例

很多情况下,我们在开发项目的过程中,都希望自己运行的某个部件只有一个实例, 比如我们天天用QT开发界面,QTCreate里帮助菜单下的关于Qt Create菜单,弹出来的关于对话框,在QTCreate...
  • gatieme
  • gatieme
  • 2014年01月08日 13:25
  • 21430

设计模式:单例模式(Singleton)

单例模式在23个设计模式中算得上是最简单的一个了,也行你会有异议,那就换成“最简单之一”,这样就严谨了很多。   单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。   适用性:当类...
  • u013256816
  • u013256816
  • 2016年03月23日 21:37
  • 4750

C++中多线程与Singleton的那些事儿

前言 前段时间在网上看到了个的面试题,大概意思是如何在不使用锁和C++11的情况下,用C++实现线程安全的Singleton。 看到这个题目后,第一个想法就是用Scott Meyer在《Effec...
  • zmlcool
  • zmlcool
  • 2016年06月11日 17:56
  • 772

设计模式(创建型)之原型模式(Prototype Pattern)

要理解原型原型模式必须先理解Java里的浅复制和深复制。有的地方,复制也叫做克隆。Java提供这两种克隆方式。 因为Java中的提供clone()方法来实现对象的克隆,所以Prototype模式实现一...
  • yanbober
  • yanbober
  • 2015年04月29日 11:28
  • 2881

为什么说Singleton 模式现在成为了反模式(Anti-Pattern)?

Why implementing a Singleton pattern in Java code is (sometimes) considered an anti-pattern in Java ...
  • hintcnuie
  • hintcnuie
  • 2016年12月16日 14:54
  • 1035

设计模式(结构型)之外观模式(Facade Pattern)

一个客户类需要和多个业务类交互,而这些业务类经常会作为整体出现,由于涉及到的类比较多,导致使用时代码较为复杂。外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类为多个业务类的调用提供统...
  • yanbober
  • yanbober
  • 2015年05月04日 09:29
  • 2416
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:javascript设计模式交流(一) ——Singleton Pattern
举报原因:
原因补充:

(最多只允许输入30个字)