SINGLETON(單件)—對象建立型模式
幾乎所有物件導向的程式中,總有一些類的對象需要是唯一的,例如,通過資料庫控制代碼到資料庫的串連是獨佔的。您希望在應用程式中共用資料庫控制代碼,因為在保持串連開啟或關閉時,它是一種開銷。再如大家最經常用的IM,如QQ,在同一台電腦,一個帳號只能有唯一的登入。
1. 問題
怎樣確保一個特殊類的執行個體是獨一無二的(它是這個類的唯一執行個體),並且這個執行個體易於被訪問呢?
2. 解決方案
1)全域變數:一個全域變數使得一個對象可以被訪問,但它不能防止你執行個體化多個對象。因為你的任何代碼都能修改全域變數,這將不可避免的引起更多調試的意外。換句話說,全域變數的狀態總是會出現一些問題的。
2)類建構函式私人和類自身的靜態方法:讓類自身負責儲存它的唯一執行個體(靜態變數)。這個類可以保證沒有其他執行個體可以被建立(通過截取建立新對象的請求) ,並且它可以提供一個訪問該執行個體的方法(靜態方法)。這就是Singleton模式。
3. 適用性
在下面的情況下可以使用單件模式
1)當類只能有一個執行個體而且客戶可以從一個眾所周知的訪問點訪問它時。
2)當這個唯一執行個體應該是通過子類化可擴充的,並且客戶應該無需更改代碼就能使用一個擴充的執行個體時。
4. 實現:
UML結構:
代碼:
<?phpclass Singleton {static private $_instance = null;//靜態成員儲存唯一執行個體/** * 私人建構函式,保證不能被外部存取 * */private function __construct() {} /** * 靜態方法將建立這個執行個體的操作並保證只有一個執行個體被建立 * * @return unknown */public static function getInstance() {if (!self::$_instance) {self::$_instance = new self();}return self::$_instance;}}
5. 效果
Singleton模式有許多優點:
1) 對唯一執行個體的受控訪問, 因為Singleton類封裝它的唯一執行個體,所以它可以嚴格的控制客戶怎樣以及何時訪問它。
2) 縮小名空間,Singleton模式是對全域變數的一種改進。它避免了那些儲存唯一執行個體的全域變數汙染名空間。
3) 允許對操作和表示的精化Singleton類可以有子類,而且用這個擴充類的執行個體來配置一個應用是很容易的。你可以用你所需要的類的執行個體在運行時刻配置應用。
4) 允許可變數目的執行個體 這個模式使得你易於改變你的想法,並允許Singleton類的多個執行個體。此外,你可以用相同的方法來控 制應用所使用的執行個體的數目。只有允許訪問 Singleton執行個體的操作需要改變。
6 .單件模式可以多個執行個體
單件模式並不是說一個類只能只有一個執行個體。假設我們使用在一個web 請求或者進程裡面。一個使用者id對應的某個類只能有唯一的執行個體。在下面的例子中,我們的User類,可以有多個執行個體,每個執行個體對應一個uid. 執行個體列表註冊到靜態變數$_instance並和uid關聯起來。最簡單的例子是我們前面提到的QQ,在同一台電腦,可以使用多帳號登入,
但一個帳號只能有唯一的登入.
代碼:
<?phpclass User {static private $_instance = array();//靜態成員儲存唯一執行個體private $_uid ;/** * 私人建構函式,保證不能被外部存取 * */private function __construct($uid ) {$this->_uid = $uid;} /** * 靜態方法將建立這個執行個體的操作並保證只有一個執行個體被建立 * * @return unknown */public static function getInstance($uid = 0) {if (!self::$_instance || !isset(self::$_instance[$uid]) ) {self::$_instance[$uid] = new self($uid);}return self::$_instance[$uid];}}
應用
在zend framework中的Zend_Controller_Front前端控制器,就是採用單價模式來設計的:
Zend_Controller_Front是Zend_Controller_Controller體系的召集人,它是FrontController設計模式的實現。
Zend_Controller_Front處理伺服器接受的所有請求,並最後負責將請求分配給ActionController(Zend_Controller_Action)
$frontController = Zend_Controller_Front::getInstance();$frontController->addModuleDirectory( “參數”);$frontController->dispatch();