单例模式 - 设计模式

单例模式(Singleton Pattern 单件模式或单元素模式)

单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

单例模式是一种常见的设计模式,在计算机系统中,线程池、缓存、日志对象、对话框、打印机、数据库操作、显卡的驱动程序常被设计成单例。

单例模式分3种:懒汉式单例、饿汉式单例、登记式单例。

单例模式有以下3个特点:

1.只能有一个实例。

2.必须自行创建这个实例。

3.必须给其他对象提供这一实例。

那么为什么要使用PHP单例模式?

PHP一个主要应用场合就是应用程序与数据库打交道的场景,在一个应用中会存在大量的数据库操作,针对数据库句柄连接数据库的行为,使用单例模式可以避免大量的new操作。因为每一次new操作都会消耗系统和内存的资源。

在以往的项目开发中,没使用单例模式前的情况如下:

//初始化一个数据库句柄

      $db = new DB(...);
      
      //比如有个应用场景是添加一条用户信息
      $db->addUserInfo();
     
      //然而我们要在另一地方使用这个用户信息,这时要用到数据库句柄资源,可能会这么做......
      function test() {
   
   $db = new DB(...);
   
   $db->getUserInfo();
   ......有些朋友也许会说,可以直接使用global关键字!
   
   global $db;......
   

的确global可以解决问题,也起到单例模式的作用,但在OOP中,我们拒绝这种编码。因为global存在安全隐患(全局变量不受保护的本质)。

全局变量是面向对象程序员遇到的引发BUG的主要原因之一。这是因为全局变量将类捆绑于特定的环境,破坏了封装。如果新的应用程序无法保证一开始就定义了相同的全局变量,那么一个依赖于全局变量的类就无法从一个应用程序中提取出来并应用到新应用程序中。

确切的讲,单例模式恰恰是对全局变量的一种改进,避免那些存储唯一实例的全局变量污染命名空间。你无法用错误类型的数据覆写一个单例。这种保护在不支持命名空间的PHP版本里尤其重要。因为在PHP中命名冲突会在编译时被捕获,并使脚本停止运行。

PHP单例模式实例:

先看图:

Delevin、博客

上面的对象图中,有一个“单例对象”,而“客户甲”、“客户乙”和“客户丙”是单例对象的三个客户对象。可以看到,所有的客户对象共享一个单例对象。而且从单例对象到自身的连接线可以看出,单例对象持有对自己的引用。

<?php
class User {    
        //静态变量保存全局实例
    private static $_instance = null; 
       
    //私有构造函数,防止外界实例化对象
    private function __construct() {
    
    }    
    //私有克隆函数,防止外办克隆对象
    
    private function __clone() {
    
    }    
    
    //静态方法,单例统一访问入口
    static public function getInstance() {        
           
           if (is_null ( self::$_instance ) || isset ( self::$_instance )) {
            self::$_instance = new self ();
        } 
        return self::$_instance;
    }  
      
    public function getName() {        
            echo 'hello world!';
    }
    
}

?>

单例模式的优缺点:

优点:

1. 改进系统的设计

2. 是对全局变量的一种改进

缺点:

1. 难于调试

2. 隐藏的依赖关系

3. 无法用错误类型的数据覆写一个单例