设计模式实践--单例模式
介绍#
数学与逻辑学中,singleton 定义为 “有且仅有一个元素的集合”。
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。
一个典型的单例模式在 php 中的实现如下:
class test
{
private static $_instance; //保存类实例的私有静态成员变量
//定义一个私有的构造函数,确保单例类不能通过new关键字实例化,只能被其自身实例化
private final function __construct()
{
echo 'test __construct';
}
//定义私有的__clone()方法,确保单例类不能被复制或克隆
private function __clone() {}
//对外提供获取唯一实例的方法
public static function getInstance()
{
//检测类是否被实例化
if ( ! (self::$_instance instanceof self) ) {
self::$_instance = new test();
}
return self::$_instance;
}
}
test::getInstance();
类自身只提供一个对外的 getInstance () 方法来获取实例,这里的关键在于用了一个静态变量 $_instance 来保存实例,静态变量是属于类的,在 php 的一次生命周期中,它会一直存在,只要有人需要拿到这个类的对象,getInstance () 就会去把唯一的 $_instance 返回回来,实现了对象的唯一性。
在容器中实现单例#
ioc 容器简介#
Sakura 框架是基于一个叫做 container 的东西的,这个 container 是一个类,它有一个叫做 $bindings 的数组,这个数组中存放的是被 bind 上去一对键值,key 是一个字符串,用来标示,value 可能是类的名字,或者一个匿名函数,总之它会告诉 container 当有人想从容器中根据 key 来取出一个对象的时候,该如何去制造出这个对象。这个概念是和 laravel 一致的。
容器中的单例#
容器中的单例模式和上述的典型单例模式最大的区别就是,典型的单例模式中类自身会保证自己只被实例化一次。但是由于在 container 中,所有对象都是通过 container 来实例化的,所以自然,保证对象的唯一性这个职责也要交给 container。
在容器中,普通对象的绑定通过 bind () 方法,示例如下:
$app = new System\Foundation\Container();
$app->bind('test', \System\test::class);
而要绑定一个单例对象的时候则用下面的方式:
$app->singleton('test', \System\test::class);
在容器的实现中,singleton () 方法的代码:
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
public function bind($abstract, $concrete = null, $shared = false)
{
if ( ! $concrete instanceof Closure ) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
}
可以看到,唯一的区别就是把 $this->bindings [$abstract] 的 shared 设置为了 true。在使用 make 方法来取出对象的时候,容器会根据当前 $abstract 对应的 shared 属性来判断是否需要单例它。
在 container 的 make () 方法中,用了如下代码:
if ($this->isShared($abstract)) {
$this->instances[$abstract] = $object;
}
isShared () 方法来判断是否为单例,如果是,则把该对象写入到容器的 $this->instances [] 中,这样当下次调用容器的 make () 方法来再次取出该对象的时候,先用如下代码进行判断,$this->instances [] 中是否已经保存有了这个对象,如果有,直接返回该对象,这样就保证了对象的唯一性。
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
完整的代码请看
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: