1. 模式定义
单例设计模式(Singleton Design Pattern):一个类只允许创建一个对象(或者实例),那这个类就是单例类,这种设计模式就叫做单例设计模式,简称单例模式。
在整个应用程序的生命周期中,任何时刻,单例类仅存在一个实例,同时这个类还必须提供一个访问该类的全局访问点。 常见使用实例:数据库连接器;日志记录器(如果有多种用途使用多例模式);锁定文件。
2. UML类图
![](https://img.haomeiwen.com/i15602817/fb47287d11771f11.png)
instance 翻译为实例
3. 示例代码
下面是项目开发中用到的一个存储当前用户信息的一个单例例子。需要注意是由于PHP是单线程,所以用户信息使用单例模式时,不会存在安全问题(问题指:多个用户登陆使用的是第一个实例化的用户信息),多注意单例的使用场景。
其UML类图如下:
![](https://img.haomeiwen.com/i15602817/b4b298c547557b44.png)
具体代码如下:
<?php
namespace DesignPattern\Creational\Singleton;
class CurrentUser
{
private static $instance = null; //当前类的实例(私有)
private static $token = ''; //当前用户的token值(私有)
private static $userInfo = []; //当前用户基本信息数组(私有)
private function __construct($token, $userInfo) //私有的构造方法,从而禁止从外部用 new 关键字创建实例(私有)
{
self::$token = $token;
self::$userInfo = $userInfo;
}
private function __clone() //克隆方法私有化,从而禁止从外部通过 clone 关键字创建实例(私有)
{
}
public static function getInstance($token, $userInfo) //用于生成当前类的实例(公共)
{
//如果$instance变量中保存的不是当前类的实例
if (!self::$instance instanceof self) {
//那么就new一个当前类,并保存在$instance中
self::$instance = new self($token, $userInfo);
}
//否则直接返回$instance
return self::$instance;
}
public static function getToken() //用于获取当前用户 token
{
return self::$token;
}
public static function getUserInfo() //用于获取当前用户信息数组 userInfo
{
return self::$userInfo;
}
}
单元测试
<?php
namespace DesignPattern\Tests;
use DesignPattern\Creational\Singleton\CurrentUser;
use PHPUnit\Framework\TestCase;
/**
* 测试单例模式
* Class SingletonTest
* @package Creational\Singleton\Tests
*/
class SingletonTest extends TestCase
{
public function testUniqueness()
{
$firstCall = CurrentUser::getInstance('token1', ['name' => 'Sylvia', 'sex' => '女']);
$firstUserInfo = $firstCall::getUserInfo();
$this->assertInstanceOf(CurrentUser::class, $firstCall);
$secondCall = CurrentUser::getInstance('token2', ['name' => 'Tom', 'sex' => '男']);
$secondUserInfo = $secondCall::getUserInfo();
$this->assertSame($firstCall, $secondCall);
$this->assertSame($firstUserInfo, $secondUserInfo);
}
/**
* @throws \ReflectionException
*/
public function testNoConstructor()
{
$obj = CurrentUser::getInstance('token1', ['name' => 'Sylvia', 'sex' => '女']);
$refl = new \ReflectionObject($obj);
$meth = $refl->getMethod('__construct');
$this->assertTrue($meth->isPrivate());
}
}
此文章为学习笔记,学习文档如下:
学院君 : https://laravelacademy.org/post/2599
极客时间 : 设计模式之美
教程源码:https://github.com/SylviaYuan1995/DesignPatternDemo
网友评论