什么是单例模式?
单例模式(Singleton Pattern)是 最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
通过单例模式可以保证系统中一个类只有一个实例,即一个类只有一个对象实例。
为什么要用单例模式?
php常常和数据库打交道,如果在应用中如果频繁建立连接对象,进行new操作的话,会消耗大料的系统内存资源,这并不是我们希望看到的。再则,在团队合作项目中,单例模式可以有效避免不同程序员new自己的对象,造成人为的系统消耗。
单例模式解决了哪些问题:
1. 保证一个类只有一个实例。 为什么会有人想要控制一个类所拥有的实例数量? 最常见的原因是控制某些共享资源 (例如数据库或文件) 的访问权限。
它的运作方式是这样的: 如果你创建了一个对象, 同时过一会儿后你决定再创建一个新对象, 此时你会获得之前已创建的对象, 而不是一个新对象。即 单例类必须自己创建自己的唯一实例。
注意, 普通构造函数无法实现上述行为, 因为构造函数的设计决定了它必须总是返回一个新对象。
2. 单例类必须给所有其他对象提供这一实例。 还记得我们用过的那些存储重要对象的全局变量吗? 它们在使用上十分方便, 但同时也非常不安全, 因为任何代码都有可能覆盖掉那些变量的内容, 从而引发程序崩溃。
和全局变量一样, 单例模式也允许在程序的任何地方访问特定对象。 但是它可以保护该实例不被其他代码覆盖。
还有一点: 你不会希望解决同一个问题的代码分散在程序各处的。 因此更好的方式是将其放在同一个类中, 特别是当其他代码已经依赖这个类时更应该如此。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
使用场景:
1、要求生产唯一序列号。
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
4、可以用在 Cache(缓存), Log(日志对象)、数据库操作 等各种资源需要被频繁调用的地方( 频繁创建和销毁的对象 )。
单例模式结构:
从具体的实现角度来讲,需要保证一下三点:
1. 单例模式的类只提供私有的构造函数
2. 类定义中含有一个该类的静态私有属性
3. 该类提供了一个静态的公有函数用于创建或者获取它本身的静态私有对象
4. 该类需要有一个私有的 clone 方法,防止被克隆
定义一个普通的类:
class Test { function a() return 111; } } echo '<hr>'; $db1 = new Test(); var_dump($db1); var_dump($db1 -> a()); $db2 = new Test(); var_dump($db2); var_dump($db2 -> a());
输出结果如图:
单例类实例:
/** * 设计模式之单例模式 * 1、什么是单例模式? * 单例模式顾名思义,就是只有一个实例。作为对象的创建模式, 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提 供这个实例。 * * 2、特点: 一是某个类只能有一个实例; 二是它必须自行创建这个实例; 三是它必须自行向整个系统提供这个实例。 * 3、常见应用 php常常和数据库打交道,如果在应用中如果频繁建立连接对象,进行new操作的话,会消耗大料的系统内存资源,这并不是我们希 望看到的。 再则,在团队合作项目中,单例模式可以有效避免不同程序员new自己的对象,造成人为的系统消耗。 ********************************************************************************** *1. 它们必须拥有一个构造函数,并且必须被标记为private *2. 它们拥有一个保存类的实例的静态成员变量 *3. 它们拥有一个访问这个实例的公共的静态方法 * 单例类不能再其它类中直接实例化,只能被其自身实例化。它不会创建实例副本,而是会向单例类内部存储的实例返回一个引用。 ********************************************************************************** * $_instance必须声明为静态的私有变量 * 构造函数必须声明为私有,防止外部程序new类从而失去单例模式的意义 * getInstance()方法必须设置为公有的,必须调用此方法以返回实例的一个引用 * ::操作符只能访问静态变量和静态函数 * new对象都会消耗内存 * 使用场景:最常用的地方是数据库连接。 * 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。 */ class Singleton { /** * 定义一个静态变量保存已经实例化的对象 * * @var self|null */ private static $instance = null; /** * 定义获取对象实例的入口,返回该实例 * * @access public * @return self */ public static function getInstance() { // 判断是否已经存在实例化对象 if ( self::$instance === null ) { // 不存在,则进行实例化 self::$instance = new self(); } return self::$instance; } /** * 构造函数私有,不允许在外部实例化----防止使用 new 创建多个实例 */ private function __construct() { // Hide the constructor } /** * 防止 clone 多个实例 */ private function __clone() { // Disable cloning //echo 'clone is forbidden'; trigger_error('Clone is not allow' ,E_USER_ERROR); } /** * 防止反序列化 */ private function __wakeup() { // Disable unserialize throw new \Exception("Cannot unserialize singleton"); } /** * 此接口用来测试单例模式 - 改变 string 的值 * * @access public * @param string $string 值 * @return void */ public function setString ($string) { $this->string = $string; } /** * 此接口用来测试单例模式 - 输出 string 的值 * * @access public * @return void */ public function dumpString () { echo($this->string); } } // 测试,第一次实例化 $test1 = Singleton::getInstance(); echo('这是第一次实例化<br><br>'); $test1->setString('哈咯,小罗'); $test1->dumpString(); echo('<br><br><br>'); // 第二次实例化 echo('这是第二次实例化<br><br>'); $test2 = Singleton::getInstance(); $test2->dumpString(); echo('<br><br><br>'); // test2 修改 string 的数据 $test2->setString('哈咯,小罗,我是 test2 修改的数据<br><br>'); // 重新执行 test1 的打印方法,看看是否改变了数据 echo('重新执行 test1 的打印方法<br><br>'); $test1->dumpString();
输出结果:
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn