设计模式教程-单件模式

简介

单件模式是设计模式里面最常见的一种,也是设计模式初学者最先碰到的一种。在php的设计模式中,单件模式往往被用来驾驽最复杂最危险的那一部分:全局变量。

 

 

    开发新手刚开始常会遇到的一个模式,单件模式,解决一个杂乱,危险而让人恐惧的问题即全局变量. 几乎在每个应用程序的每个地方都有需要被访问的组件。 配置变量就是其最突出的例子。 开发新手常会把一个调试变量申明为全局,想在那里访问就在那里访问。 随着项目的开发你会发现这样会使应用程序得维护十分艰难。

    全局变量有什么问题呢? 在这个问题上我不准备花太多时间。 这里是一段Global Variables上面 wikipedia页面片段选摘:

   它们常被看作是败笔,就是因为它们的非局域性:全局变量在任何地方都有修改的可能性,(除非它所存贮的位置受保护 )而且不可与程序的其它部分相分离。一个全局变量因而很有可能产生相互依存性,而增大相互依存性就会使问题变得复杂。

问题

   首先阅读这系列文章中的 介绍部分, 其中讨论了模式背后的总体概念。

   继续,假设应用程序有一个 Config类,这个类存储了 应用程序的偏好相关值. 当然这些值需可以从应用程序任何类中访问。一遍一遍初始化Config类代价太大而且也没有必要。 此外,如果你需要从A类中创建一个新的在B类中引用的动态 config 变量会怎么样呢? 由于 Config 的所有实例都彼此相分离,所以这种想法是无法实现的。

   请注意: 我会在例子中用到php5 代码。

   

view plain copy to clipboard print http://mikebernat.com/blog/Design_Patterns_-_The_Singleton

  1. <?php   
  2. class Config {    
  3.   public $debug = 0;  
  4. }   
  5. class A {   
  6.     public function doSomething() {  
  7.         $config = new Config();   
  8.      $config->debug = 1;   
  9.   }   
  10. }   
  11. class B {   
  12.   public function doSomethingElse() {   
  13.     $config = new Config();   
  14.     echo $config->debug;   
  15.   }   
  16.  }    
  17. $a = new A;   
  18. $b = new B;
  19. $a->doSomething();   
  20. $b->doSomethingElse();   
  21. // Output: 0  
  22. ?>   

<?php class Config { public $debug = 0; } class A { public function doSomething() { $config = new Config();  $config->debug = 1; } } class B { public function doSomethingElse() { $config = new Config(); echo $config->debug;  } } $a = new A; $b = new B; $a->doSomething(); $b->doSomethingElse(); // Output: 0 ?>

 

    如你所看到的那样, Config的每个例子都彼此相分离。 改变类中一个例子的成员属性不会改变其它例子成员属性。 如何这样解决这个问题:保留这看起来有用的全局变量同时符合面向对象的程序设计 的严格标准?

解决方法

    进入: The Singleton。

    单件模式可以使类的例子保持不变,不管它被“初始化”了多少次。 我把初始化用引号引起来,因为不是真的初始化了。它像全局变量那样作用。 如果你改变了一个类中的一个属性,就会在所有其它地方都表现出来。 看看在下面例子中如何使用单件模式修改 Config类。

 

view plain copy to clipboard print http://mikebernat.com/blog/Design_Patterns_-_The_Singleton

  1. <?php   
  2. class Config {   
  3.     private static $instance;   
  4.     
  5.     private function __construct() { }   
  6.        
  7.     public static function getInstance() {   
  8.         if (emptyempty(self::$instance)) {   
  9.             self::$instance = new Config;   
  10.         }   
  11.         return self::$instance  
  12.   }   
  13. }      
  14. ?>  

<?php class Config { private static $instance; private function __construct() { } public static function getInstance() { if (empty(self::$instance)) { self::$instance = new Config; } return self::$instance } } ?>

 

    你首先要注意是静态属性 $instance。 这样就会在运行的时候保持类中的唯一实例。 构造函数已经设为了非公开,这就在以常用方式初始化这个类会给出错误结果。相反,我们驱使这个类的用户访问静态方法getInstance()。 getInstance() 就是单件模式神奇之处。 如果函数是第一次调用,就会产生一个新实例,存放在$instance。 而后,返回此类中这个实例。

那这是什么意思呢? 我们回头来看原来的例子。

 

view plain copy to clipboard print http://mikebernat.com/blog/Design_Patterns_-_The_Singleton

  1. <?php   
  2. class Config {    
  3.   public $debug = 0;   
  4.  
  5.   private static $instance;   
  6.         
  7.   private function __construct() { }   
  8.   public static function getInstance() {   
  9.     if (emptyempty(self::$instance)) {   
  10.        self::$instance = new Config;   
  11.    }   
  12.     return self::$instance  
  13.   }   
  14. }   
  15. class A {   
  16.   public function doSomething() {   
  17.     $config = Config::getInstance();   
  18.     $config->debug = 1;
  19.   }   
  20. }   
  21. class B {   
  22.   public function doSomethingElse() {  
  23.     $config = Config::getInstance();   
  24.     echo $config->debug;    
  25.   }   
  26. }   
  27. $a = new A;    
  28. $b = new B;
  29. $a->doSomething();   
  30. $b->doSomethingElse();   
  31. // Output: 1
  32. ?>  

<?php class Config { public $debug = 0; private static $instance; private function __construct() { } public static function getInstance() { if (empty(self::$instance)) { self::$instance = new Config; } return self::$instance } } class A { public function doSomething() { $config = Config::getInstance(); $config->debug = 1; } } class B { public function doSomethingElse() { $config = Config::getInstance(); echo $config->debug; } } $a = new A; $b = new B; $a->doSomething(); $b->doSomethingElse(); // Output: 1 ?>

 

    如你所见,开始的 Config函数已由getInstance()静态调用替换. 这次,改变类A属性$debug时,这一操作也会在其它类中实现。

结果

    使用单件模式节省大量服务器内存和CPU周期,因为它不需要一次一次地初始化(这取决于你使用那种语言)。保存 变量 应用程序.

    不理想的是,单件模式也还是有全局变量所存在的问题。 产生了依存关系但很难发现依存关系。这有损于模式化。 不过,如果保守小心使用单件模式,我想对你还是大有帮助的.

其他意见

    单件. 不单是因其非常有用而有其它原因。 不是因为合理使用时怎样的有效,开发者. 不管怎样,先看看这里的几个例子:

   编辑: 如果你遵守模式定义,在合适的状况下使用它,我想这些言论就有点吹毛求疵了:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值