设计模式实践--单例模式
介绍
数学与逻辑学中,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 协议》,转载必须注明作者和本文链接