简单说来,单例模式的作用就是保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例都只存在一个,同时这个类还必须提供一个访问该类的全局访问点。
应用场景
数据库连接器(mysql|Oracle|sqlServer);
缓存/日志(file|redis|memcached);
在应用中锁定文件;
优缺点
优点
- 确保所有的对象都访问一个实例
- 只存在一个实例对象,节约系统资源,无须频繁创建和销毁的对象。
缺点
- 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
- 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
- 单例类的职责过重,在一定程度上违背了“单一职责原则”。
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。
缺点是网上找的,个人认为这不算缺点,用对场景就没有缺点!!!
示例代码
这里以连接数据库为例,使用单例模式,多次调用只连接一次数据库。
<?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),建议弃用』如何理解?
请猛戳 这里>>