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


原文出处: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>
复制代码运行代码另存代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值