Pattern: 單例模式
Class Diagram: 資料庫連線
需求一:客戶想要能與資料庫連線的類別
1 2 3 4 5 6 7 8 9 10 11
| <?php
namespace App\SingletonPattern\DBConnection;
class DBConnection { public function __construct() { } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
namespace App\SingletonPattern\DBConnection;
class Program {
public function getDBConnection() { return new DBConnection(); } }
|
需求二:客戶說希望能修改成只建立唯一的連線。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| <?php
namespace App\SingletonPattern\DBConnection;
class DBConnection { private static $instance = null;
private function __construct() { }
private function __clone() { }
private function __wakeup() { }
public static function getInstance() { if (static::$instance === null) { static::$instance = new self(); }
return self::$instance; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
namespace App\SingletonPattern\DBConnection;
class Program {
public function getDBConnection() { return DBConnection::getInstance(); } }
|
在這裡我們一共用了兩個技巧:
透過公開的靜態方法,呼叫私有的建構函式,
來保證 DBConnection 的唯一。
在 getInstance() 中,我們會判斷 $instance 是否為 null,
才決定是否實例化,為單例模式中Lazy Initialization的形式。
單例模式還有以下其他形式(處理多線程):
- Eager Initialization (類別 $instance 一開始就建立,PHP 貌似不支援)
- Synchronized(同步方法)
- Double-Checked Locking(雙重檢查加鎖)
在 PHP 中,web 環境的每一個 request 都是獨立的線程,
而 cli 環境,則需裝 pthreads 才能實現多線程。
因為 PHP 鮮少使用多線程,算是巧妙地閃躲了單例模式的使用問題。
將來有機會會以其他程式語言,再次撰寫相關範例。
ʕ •ᴥ•ʔ:看似簡單,背後卻有許多細節的反模式。