介紹
數學與邏輯學中,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 協議》,轉載必須註明作者和本文連結