單例模式,正如其名,允許我們建立乙個而且只能建立乙個物件的類。
這在整個系統的協同工作中非常有用,特別明確了只需乙個類物件的時候。
那麼,為什麼要實現這麼奇怪的類,只例項化一次?
在很多場景下會用到,如:配置類、session類、database類、cache類、file類等等。
這些只需要例項化一次,就可以在應用全域性中使用。
本文我們以資料庫類為例。
1 問題
如果沒有使用單例模式,會有什麼樣的問題?
如下是乙個簡單的資料庫連線類,它沒有使用單例模式。
class database }
然後建立3個物件:
$config = array(
'db_name' => 'test',
'db_host' => 'localhost',
'db_user' => 'root',
'db_pass' => 'root'); $db1 = new database($config); var_dump($db1); $db2 = new database($config); var_dump($db2); $db3 = new database($config); var_dump($db3);
這種情況下,每當我們建立乙個這個類的例項,就會新增乙個到資料庫的連線。
開發者每在乙個地方例項化一次這個類,就會在那裡多乙個資料庫連線。
不知不覺中,開發者就犯了個錯誤,給資料庫和伺服器效能帶來巨大的影響。
上面的**輸入如下:
object(database)[1] public 'db' => object(pdo)[2]object(database)[3] public 'db' => object(pdo)[4]object(database)[5] public 'db' => object(pdo)[6]
每個物件都分配乙個新的資源id,都是新的引用,它們占用3個的記憶體空間。
如果有100個物件建立,就會占用記憶體中100塊不同的空間,而其餘99塊並非是必須的。
2 解決
開發者怎樣使用基礎框架,如何資料庫連線,這很難控制。
如果在**評審階段再找出問題,又會浪費大量的人力物力。
要解決這樣的問題,我們可以控制住基類,在源頭上限制這個類,使其無法生成多個物件,如果已經生成過,直接返回。
於是,我們的目標就是,控制資料庫類,使其生成一次而且只能生成一次物件。
如下就是單例模式連線資料庫**:
class database
// 這是獲取當前類物件的唯一方式
public static function getinstance($config = array())
return self::$instance;
} // 獲取資料庫控制代碼方法
public function db()
// 宣告成私有方法,禁止轉殖物件
private function __clone(){}
// 宣告成私有方法,禁止重建物件
private function __wakeup(){} }
再通過getinstance()方法使用類物件,
$config = array(
'db_name' => 'test',
'db_host' => 'localhost',
'db_user' => 'root',
'db_pass' => 'root'); $db1 = database::getinstance($config); var_dump($db1); $db2 = database::getinstance($config); var_dump($db2); $db3 = database::getinstance($config); var_dump($db3);
輸出資訊如下:
object(database)[1] private 'db' => object(pdo)[2]object(database)[1] private 'db' => object(pdo)[2]object(database)[1] private 'db' => object(pdo)[2]
對比兩個輸出可以看出,單例模式中,不同物件獲得的資源id是一樣的。
也就是說,雖然我們用getinstance()獲取database類物件3次,其實引用的是乙個記憶體空間,pdo也只連線了資料庫一次。
以上的例子是資料庫連線類,要使用資料庫,在應用這樣獲得連線控制代碼:
$db = database::getinstance($config)->db();
如果是其他類,則按需要修改資料庫相關的**,單例實現部分保留。
3 特點
單例模式的特點是4私1公:乙個私有靜態屬性,構造方法私有,轉殖方法私有,重建方法私有,乙個公共靜態方法。
其他方法根據需要增加。
最基礎的單例模式**如下:
class singleton
return self::$instance;
} private function __construct(){}
private function __clone(){}
private function __wakeup(){} }
$instance用以儲存類的例項化,getinstance()方法提供給外部本類的例項化物件:
對應的uml圖如下,
單例模式在應用請求的整個生命週期中都有效,這點類似全域性變數,會降低程式的可測試性。
大部分情況下,也可以用依賴注入來代替單例模式,避免在應用中引入不必要的耦合。
所以,對於僅需生成乙個物件的類,首先考慮用依賴注入方式,其次考慮用單例模式來實現。
標籤: 千鋒設計模式php
輕鬆搞定設計模式 單例模式
單例模式是一種物件建立型模式,使用單例模式可以保證為乙個類只生成唯一的例項物件。也就是說,在整個程式空間中,該類只存在乙個例項物件。在應用系統開發中如果有以下需求 因為單例模式可以保證為乙個類只生成唯一的例項物件,所以這些情況一般採用單例設計模式。單例模式分為餓漢式和懶漢式兩種。懶漢式 示例如下 c...
PHP單例模式
模式對於oop開發人員尤其有用,因為他有助於建立穩定的api,並且仍然保持一定的靈活度。一種模式可以幫助我們定義負責完成特定任務的物件,還可以允許我們全部修改掉某個類而不用修改與這些類打交道的 前者被稱為類的職責,後者被稱為類的多型性。單例模式被當作職責模式,他用來在應用程式中建立乙個單一的功能訪問...
php單例模式
單例模式 單例類 1 建構函式需要標記為private 訪問控制 防止外部 使用new操作符建立物件 單例類不能在其他類中例項化,只能被其自身例項化 2 擁有乙個儲存類的例項的靜態成員變數 3 擁有乙個訪問這個例項的公共的靜態方法 常用getinstance 方法進行例項化單例類,通過instanc...