简单说来,单例模式的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个,同时这个类还必须提供一个访问该类的全局访问点。

应用场景

数据库连接器(mysql|Oracle|sqlServer);

缓存/日志(file|redis|memcached);

在应用中锁定文件;

优缺点

优点

  1. 确保所有的对象都访问一个实例
  2. 只存在一个实例对象,节约系统资源,无须频繁创建和销毁的对象。

缺点

  1. 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
  2. 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
  3. 单例类的职责过重,在一定程度上违背了“单一职责原则”。
  4. 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

缺点是网上找的,个人认为这不算缺点,用对场景就没有缺点!!!

示例代码

这里以连接数据库为例,使用单例模式,多次调用只连接一次数据库。

<?php

namespace app\database\driver;

class Mysql
{
    /**
     * @var Mysql
     */
    private static $instance;

    /**
     * @var \PDO
     */
    private $connection;

    /**
     * 通过懒加载获得实例(在第一次使用的时候创建)
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * private,不允许从外部调用以防止创建多个实例
     * 要使用单例,必须通过 Connection::getInstance() 方法获取实例
     */
    private function __construct()
    {

    }

    /**
     * 获取数据库连接
     * @return \PDO
     */
    public function getConnection()
    {
        if (null === $this->connection) {
            $this->connection = new \PDO("mysql:host=127.0.0.1;port=3306;dbname=test;charset=utf8", 'root', 'abc-123');
        }
        return $this->connection;
    }

    /**
     * 防止实例被克隆(这会创建实例的副本)
     */
    private function __clone()
    {
    }

    /**
     * 防止反序列化(这将创建它的副本)
     */
    private function __wakeup()
    {
    }
}

连接数据库并执行语句

<?php

use app\database\driver\Mysql;

$db = Mysql::getInstance()->getConnection();

// 无论调用多少次,始终仅连接一次数据库
$db = Mysql::getInstance()->getConnection();
$db = Mysql::getInstance()->getConnection();

$statement = $db->query("SHOW databases");
$res = $statement->fetchAll();

最后

【单例模式】被公认为是 反面模式(Anti Pattern),建议弃用』如何理解?

请猛戳 这里>>