PHP設計模式(1):單例模式(Singleton)

前言:這個是作者扔在某書的日誌,搬過來!

什麼是單例模式

顧名思義,就是隻有一個實例。作為對象的創建模式,單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。

為什麼使用單例模式
  1. PHP的應用主要在於數據庫應用,一個應用中會存在大量的數據庫操作,在使用面向對象的方式開發時,如果使用單例模式,
    則可以避免大量的 new 操作消耗的資源,還可以減少數據庫連接這樣就不容易出現 too many connections 情況。
  2. 如果系統中需要有一個類來全局控制某些配置信息,那麼使用單例模式可以很方便的實現。
  3. 在一次頁面請求中,便於進行調試,因為所有的代碼(例如數據庫操作類db)都集中在一個類中,我們可以在類中設置鉤子,輸出日誌,從而避免到處 var_dump,echo。


PHP設計模式(1):單例模式(Singleton)

PHP設計模式(1):單例模式(Singleton)

單例模式的實現
  1. 私有化一個屬性用於存放唯一的一個實例
  2. 私有化構造方法,私有化克隆方法,用來創建並只允許創建一個實例
  3. 公有化靜態方法,用於向系統提供這個實例
代碼實現
<code>class Singleton
{
// 存放實例
private static $_instance = null;

// 私有化構造方法
private function __construct()
{
echo '單例模式的實例被構造了';
}

// 私有化克隆方法
private function __clone() {}

// 公有化獲取實例方法
public static function getInstance()
{
if (!(self::$_instance instanceof Singleton)) {
self::$_instance = new Singleton();
}
return self::$_instance;
}
}


$singleton = Singleton::getInstance();/<code>
優點:
  1. 因為靜態方法可以在全局範圍內被訪問,當我們需要一個單例模式的對象時,只需調用getInstance方法,獲取先前實例化的對象,無需重新實例化。
  2. 由於單例模式在內存中只有一個實例,減少內存開支,特別是一個對象需要頻繁地創建銷燬時,而且創建或銷燬時性能又無法優化,單例模式就非常明顯了
  3. 由於單例模式只生成一個實例,所以,減少系統的性能開銷,當一個對象產生需要比較多的資源時,如讀取配置,產生其他依賴對象時,則可以通過在應用啟動時直接產生一個單例對象,然後永久駐留內存的方式來解決。
  4. 單例模式可以避免對資源的多重佔用,例如一個寫文件操作,由於只有一個實例存在內存中,避免對同一個資源文件的同時寫操作
  5. 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如,可以設計一個單例類,負責所有數據表的映射處理。
缺點:
  1. 單例模式一般沒有接口,擴展很困難,若要擴展,除了修改代碼基本上沒有第二種途徑可以實現。
  2. 單例對象如果持有Context,那麼很容易引發內存洩漏,此時需要注意傳遞給單例對象的Context最好是Application Context。
使用 Trait 關鍵字實現類似於繼承單例類的功能
<code>Trait Singleton
{
//存放實例
private static $_instance = null;

//私有化克隆方法
private function __clone() {}

//公有化獲取實例方法
public static function getInstance()
{
$class = __CLASS__;
if (!(self::$_instance instanceof $class)) {
self::$_instance = new $class();
}
return self::$_instance;
}
}

class DB
{
private function __construct()
{
echo __CLASS__ . PHP_EOL;
}
}

class DBHandle extends DB

{
use Singleton;
private function __construct()
{
echo '單例模式的實例被構造了';
}
}

$handle = DBHandle::getInstance();

// 注意若父類方法為public,則子類只能為pubic,若父類為private,子類為public,protected,private都可以。/<code>
單例模式特點(三私一公)
  1. 私有的構造方法(防止類外實例化)
  2. 私有的克隆方法(防止通過克隆生成對象)
  3. 私有的靜態屬性(保存類的實例)
  4. 公有的靜態方法(調取這個類相當一個接口)

補充,大多數書籍介紹單例模式,都會講三私一公,公有化靜態方法作為提供對象的接口,私有屬性用於存放唯一一個單例對象。私有化構造方法,私有化克隆方法保證只存在一個單例。
但實際上,雖然我們無法通過 new 關鍵字和 clone 出一個新的對象,但我們若想得到一個新對象。還是有辦法的,那就是通過序列化和反序列化得到一個對象。私有化 sleep() 和 wakeup() 方法依然無法阻止通過這種方法得到一個新對象。或許真得要阻止,你只能去 __wakeup 添加刪除一個實例的代碼,保證反序列化增加一個對象,你就刪除一個。不過這樣貌似有點怪異。


分享到:


相關文章: