程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP綜合 >> php設計模式介紹之單條模式

php設計模式介紹之單條模式

編輯:PHP綜合

幾乎所有面向對象的程序中,總有一兩個資源被創建出來,在程序應用中持續被共享使用。例如,這 樣的一個資源,在一個電子商務程序的數據庫連接中使用:這個連接在應用程序啟動時初始化,程序於 是可以有效的執行;當程序結束時,這個連接最終被斷開並銷毀。如果是你寫的代碼,沒必要在每時每 刻創建一個數據庫連接,這樣非常低效。已經建立好的連接應該能被你的代碼簡單重復的使用。這個問 題就是,基於以上要求你將如何進行這個數據庫連接?(或者連接其它被循環使用的唯一資源,比如一 個開放文件或者一個隊列。)

問題

你怎樣確保一個特殊類的實例是獨一無二的(它是這 個類的唯一實例),並且它很存取容易呢?

解決方案

當然,全局變量是顯而易見的解決 方案。但它就像潘多拉的盒子(正確的判斷來自經驗,而錯誤的判斷產生經驗。這句諺語就是這個意思 。),你的任何代碼都能修改全局變量,這將不可避免的引起更多調試的意外。換句話說,全局變量的 狀態總是會出現一些問題的,(這裡有一個關於全局變量使用問題不錯的描述, http://c2.com/cgi/wiki?GlobalVariablesAreBad)。

當你需要一個特殊類的唯一實例時,使用 這個名字叫單件的模式。基於單件模式的類能實例化和初始化這個類的一個實例,並且提供每時每刻絕 對相同的連接。一般情況下使用名為getInstance()的靜態方法實現。

關鍵問題是,如何在每時 每刻獲得一個精確統一的實例。請看下面的例子:

// PHP4

function TestGetInstance() {
$this->assertIsA(
$obj1 =& DbConn::getInstance(),
‘DbConn’,
‘The returned object is an instance of DbConn’);
$this->assertReference(
$obj1,
$obj2 =& DbConn::getInstance(),
‘Two calls to getInstance() return the same object’);
}

注釋:assertReference

assertReference() 方法確保 兩個被傳遞的參數引用自相同的PHP變量。

在PHP4中,這裡斷言兩個被測試的參數的卻是相同的 對象。assertReference() 這個方法在移植到PHP5以後也許就不推薦使用了。

這個test方法有兩 個斷言:第一個判斷第調用靜態方法DbConn::getInstance()返回的值是DbConn對象的實例,第二個用來 判斷第二次調用getInstance()方法返回得值引用的是相同的對象實例,這意味著他們使用的是同一個對 象。

除了斷言代碼預期的執行結果,Test也預示了getInstance()的正確用法(PHP4): $local_conn_var=&DbConn::getInstance()。引用(=&)靜態方法的返回值賦值給了這個局部 變量。

再寫另外一段測試代碼:直接用“new”來實例化一個單件類會引起某些類型 的錯誤。test代碼如下:

function TestBadInstantiate() {
$obj =& new DbConn;
$this->assertErrorPattern(
‘/(bad|nasty|evil|do not|don\’t|warn).*’.
‘(instance|create|new|direct)/i’);
}

這段代碼直接創建了一個 DbConn 的實例,將會引起PHP報錯。為了讓代碼更穩定,我們 用PCRE正則表達式來匹配報錯信息。(顯示報錯信息的確切措詞並不重要。)

樣本代碼

單件模式是一個很有趣的模式。讓我們用PHP4和PHP5兩種方式來探究它的實現過程,現在從PHP4開始。

全局方式

理論上說,一個全局變量可以生成一個完美的單件,但全局變量可能被修改: 在代碼運行過程中,不能保證全局變量指向的是一個對象。因而,不讓全局變量在全局直接引用,就可 以減少“太隨意訪問”這個全局變量的問題。比如說,這段代碼使用一個非常長而且獨特的 名字,從而“隱藏”了全局變量的引用。

class DbConn {
function DbConn($fromGetInstance=false) {
if (M_E != $fromGetInstance) {
trigger_error (‘The DbConn class is a Singleton,’
.’ please do not instantiate directly.’);
}
}
function &getInstance() {
$key = ‘__some_unique_key_for_the_DbConn_instance__’;
if (!(array_key_exists ($key, $GLOBALS) && is_object($GLOBALS[$key])
&& ‘dbconn’ == get_class($GLOBALS[$key]) )) {
$GLOBALS[$key] =& new DbConn(M_E);
}
return $GLOBALS[$key];
}
}

在DbConn的構造函數中,你可能對 $fromGetInstance的默認參數感到疑惑。在對象被直接實例化時,它能夠提供(很微弱的)保護:除非 這個默認值變成e (在PHP的數學常量中 M_E = 2.718281828459),否則這段代碼會報錯。

表 示成一個UML類圖,解決辦法如下:

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved