日韩天天综合网_野战两个奶头被亲到高潮_亚洲日韩欧美精品综合_av女人天堂污污污_视频一区**字幕无弹窗_国产亚洲欧美小视频_国内性爱精品在线免费视频_国产一级电影在线播放_日韩欧美内地福利_亚洲一二三不卡片区

《PHP設(shè)計(jì)模式介紹》第五章 注冊(cè)模式(2)_PHP教程

編輯Tag賺U幣
教程Tag:暫無Tag,歡迎添加,賺取U幣!

推薦:《PHP設(shè)計(jì)模式介紹》第四章 單件模式
幾乎所有面向?qū)ο蟮某绦蛑�,總有一兩個(gè)資源被創(chuàng)建出來,在程序應(yīng)用中持續(xù)被共享使用。例如,這樣的一個(gè)資源,在一個(gè)電子商務(wù)程序的數(shù)據(jù)庫連接中使用:這個(gè)連接在應(yīng)用程序啟動(dòng)時(shí)初始化,程序于是

測(cè)試又通過了!現(xiàn)在我們想最終特性進(jìn)發(fā):給定一個(gè)屬性key,注冊(cè)模式類的get()方法將返回一個(gè)對(duì)特定對(duì)象的引用。一下為符合這一要求的測(cè)試用例。

代碼:

class RegistryPHP4TestCase extends UnitTestCase
{function testRegistryIsSingleton() { /*...*/ }
function testEmptyRegistryKeyIsInvalid() { /*...*/ }
function testEmptyRegistryKeyReturnsNull() { /*...*/ }
function testSetRegistryKeyBecomesValid() { /*...*/ }
function testSetRegistryValueIsReference()
{$reg =& Registry::getInstance();$test_value = 'something';
$reg->set('key', $test_value);
$this->assertReference($test_value, $reg->get('key'));
//another way to test the reference
$test_value .= ' else';
$this->assertEquual('something else',$reg->get('key'));
}
}

以下為注冊(cè)模式類的完整實(shí)現(xiàn)代碼。

代碼:

class Registry
{var $_store = array();
function isValid($key)
{return array_key_exists($key, $this->_store);}
function &get($key)
{if (array_key_exists($key, $this->_store))
return $this->_store[$key];}
function set($key, &$obj)
{$this->_store[$key] =& $obj;}
function &getInstance()
{static $instance = array();
if (!$instance) $instance[0] =& new Registry;
return $instance[0];
}
}

“注冊(cè)模式”的get()方法會(huì)返回一個(gè)對(duì)象引用。類似的,set()方法的$obj參數(shù)要求得到一個(gè)對(duì)象引用并被賦值$this->_store[$key].。get()和set()方法的聯(lián)合恰當(dāng)使用能夠滿足assertReference()測(cè)試。

作者注:

“注冊(cè)模式”的getRegistry::get()方法的代碼應(yīng)該寫成@$this->_store[$key;]的形式,但是最好避免使用錯(cuò)誤抑制符,使用錯(cuò)誤抑制符的代碼會(huì)變的摸棱兩可,你需要花費(fèi)額外的時(shí)間去了解你是否會(huì)再次訪問這段代碼。array_key_exists()方法指出了應(yīng)該避免的錯(cuò)誤。

PHP5中,對(duì)象句柄(引用)帶來了革命性的變化——你可以從對(duì)象引用的困境中解脫出來。事實(shí)上PHP5中注冊(cè)模式的實(shí)現(xiàn)變的簡(jiǎn)單多了。因?yàn)槟阍僖膊挥脫?dān)心因?yàn)闆]有通過引用傳遞對(duì)象而引起致命錯(cuò)誤的情況下使用聯(lián)合數(shù)組。在PHP5中,你甚至能在注冊(cè)模式中混和使用對(duì)象和變量。

一個(gè)例子:

在實(shí)際應(yīng)用中“注冊(cè)模式”會(huì)是什么樣子?在網(wǎng)絡(luò)應(yīng)用程序開發(fā)中,通常我們只擁有一個(gè)數(shù)據(jù)庫連接。(因此,廣泛使用“單一模式”管理數(shù)據(jù)連接)但是,比如,由于歷史遺留原因:你的應(yīng)用的客戶數(shù)據(jù)庫與你的在線訂單數(shù)據(jù)庫是分開的,你的DBA又把你的舊訂單轉(zhuǎn)移到一個(gè)存檔數(shù)據(jù)庫中,而且它與你的客戶數(shù)據(jù)庫及訂單(現(xiàn)有,最近)數(shù)據(jù)庫也是完全隔離的。那么,你怎么才能方便地管理三個(gè)數(shù)據(jù)庫連接而不用創(chuàng)建三個(gè)單獨(dú)的“單一模式”呢?答安就是使用“注冊(cè)模式”。

代碼:

class DbConnections extends Registry {}

注:當(dāng)你在你的代碼中引入設(shè)計(jì)模式時(shí),你的類名應(yīng)該仍能反映他的角色和功能而沒有必要使用模式的名字。使用模式的名字注釋代碼對(duì)與你的項(xiàng)目以外的程序員交流非常有幫助。但是在你的項(xiàng)目?jī)?nèi),類的名字應(yīng)該適合項(xiàng)目本身而且能夠被項(xiàng)目成員很好的理解。雖然本章范例中的類名反映了設(shè)計(jì)模式的名字以及特定的實(shí)現(xiàn)方式,但是這并不是必須的。這僅僅是為了例子的清晰明了而不是好的命名規(guī)范。

DbConnections類是一個(gè)單件模式類,又繼承了注冊(cè)模式——DbConnections綜合了兩者的優(yōu)點(diǎn)。

以下的代碼片斷創(chuàng)建并在注冊(cè)模式類中存儲(chǔ)了對(duì)每一個(gè)數(shù)據(jù)庫的連接。

代碼:

//initial setup, somewhere near the start of your script
$dbc =& DbConnections::getInstance();
$dbc->set(
'contacts',
new MysqlConnection('user1', 'pass1', 'db1', 'host1'));
$dbc->set(
'orders',
new MysqlConnection('user2', 'pass2', 'db2', 'host2'));
$dbc->set(
'archives',
new MysqlConnection('user3', 'pass3', 'db3', 'host3'));

在其他類中將注冊(cè)模式類連同數(shù)據(jù)一起載入就可以使用不同的連接了。

代碼:

// domain model classes
class Customer {
var $db;
function Customer() {
$dbc =& DbConnections::getInstance();
$this->db =& $dbc->get('contacts');
}
//...
}
class Orders {
var $db_cur;
var $db_hist;
function Contact() {
$dbc =& DbConnections::getInstance();
$this->db_cur =& $dbc->get('orders');
$this->db_hist =& $dbc->get('archive');
}
//...
}

一個(gè)類依據(jù)客戶數(shù)據(jù)庫建模,另一個(gè)類依據(jù)歷史和現(xiàn)在的客戶訂單建模。取得正確的數(shù)據(jù)庫鏈接需要兩個(gè)步驟:找到注冊(cè)模式類,從中找出與給定的屬性(key)相匹配的對(duì)象。

將注冊(cè)模式實(shí)現(xiàn)為單件模式:

如前所述,把注冊(cè)模式實(shí)現(xiàn)為單件模式有很多實(shí)現(xiàn)方式。

第一步,將注冊(cè)模式實(shí)現(xiàn)為單件對(duì)象,(作者注:我們?cè)诘谒恼?mdash;—The Singleton Pattern末尾簡(jiǎn)單討論過)。

按照這種設(shè)計(jì),注冊(cè)模式類的任何一個(gè)實(shí)例都將訪問同一個(gè)數(shù)組。我們把這個(gè)新類叫做RegistryGlobal以區(qū)別于我們前面開發(fā)的類,并反映這種實(shí)現(xiàn)方式的特性。

以下為反映這種思想的測(cè)試用例(它應(yīng)該看起來很熟悉)。

代碼:

class RegistryGlobalPHP4TestCase extends UnitTestCase {
function testRegistryGlobal() {
$reg =& new RegistryGlobal;
$this->assertFalse($reg->isValid('key'));
$this->assertNull($reg->get('key'));
$test_value = 'something';
$reg->set('key', $test_value);
$this->assertReference($test_value, $reg->get('key'));
}
}

實(shí)現(xiàn)代碼如下所示:

class RegistryGlobal {
var $_store = array();
function isValid($key) {
return array_key_exists($key, $this->_store);
}
function &get($key) {
if (array_key_exists($key, $this->_store))
return $this->_store[$key];
}
function set($key, &$obj) {
$this->_store[$key] =& $obj;
}
}

isValid(), get(),和set()方法與我們前面開發(fā)的注冊(cè)模式類完全相同。
下一步:我們來編寫驗(yàn)證RegistryGlobal類是單件模式的測(cè)試用例。

代碼:

class RegistryGlobalPHP4TestCase extends UnitTestCase {
function testRegistryGlobal() { /*...*/ }
function testRegistryGlobalIsMonoState() {
$reg =& new RegistryGlobal;
$reg2 =& new RegistryGlobal;
$this->assertCopy($reg, $reg2);
$test_value = 'something';
$reg->set('test', $test_value);
$this->assertReference(
$reg->get('test')
,$reg2->get('test'));
}
}

這里測(cè)試用例創(chuàng)建了RegistryGlobal類的兩個(gè)實(shí)例,并確認(rèn)他們不是對(duì)同一對(duì)象的引用——在一個(gè)實(shí)例內(nèi)設(shè)置一個(gè)對(duì)象的屬性值(value),最后證實(shí)兩個(gè)實(shí)例返回相同的對(duì)象。若測(cè)試通過RegistryGlobal類就擁有單態(tài)的行為。

代碼:

define('REGISTRY_GLOBAL_STORE', '__registry_global_store_key__');
class RegistryGlobal
{var $_store;
function RegistryGlobal()
{if
(!array_key_exists(REGISTRY_GLOBAL_STORE, $GLOBALS)||!is_array($GLOBALS[REGISTRY_GLOBAL_STORE])) {$GLOBALS[REGISTRY_GLOBAL_STORE] = array();
}
$this->_store =& $GLOBALS[REGISTRY_GLOBAL_STORE];
}
function isValid($key)
{return array_key_exists($key, $this->_store);}
function &get($key)
{if (array_key_exists($key, $this->_store)) return $this->_store[$key];}
function set($key, &$obj) {
$this->_store[$key] =& $obj;
}
}

本方法中的神奇之處在于$this->_store =& $GLOBALS[REGISTRY_GLOBAL_STORE;] 這一行,引用操作符將全局?jǐn)?shù)組綁定到實(shí)例變量$_store上。這是單件模式實(shí)現(xiàn)的關(guān)鍵所在:每次在對(duì)象中使用$this->_store變量時(shí),作用反映到全局變量中。

但是并不推薦基于全局變量的解決方案。如果PHP4支持這一特性的話,靜態(tài)類變量會(huì)是更好的解決方案。然而,我們可以在代碼中通過引用實(shí)現(xiàn)靜態(tài)類變量嗎?

測(cè)試與 RegistryGlobal 類的測(cè)試相似。

class RegistryMonoStatePHP4TestCase extends UnitTestCase {
function testRegistryMonoState() {
$this->assertCopy(
$reg =& new RegistryMonoState;
$reg2 =& new RegistryMonoState);
$this->assertFalse($reg->isValid(‘key’));
$this->assertNull($reg->get(‘key’));
$test_value = ‘something’;
$reg->set(‘key’, $test_value);
$this->assertReference($reg->get(‘key’), $reg2->get(‘key’));
}
}

要自己實(shí)現(xiàn)類靜態(tài)變量,可以將一個(gè)對(duì)函數(shù)靜態(tài)變量的引用綁定到類的實(shí)例變量上。

class RegistryMonoState {var $_store;
function &_initRegistry() { static $store = array(); return $store;
}
function RegistryMonoState() {
$this->_store =& $this->_initRegistry();
}
function isValid($key) {
return array_key_exists($key, $this->_store);
}
function &get($key) {
if (array_key_exists($key, $this->_store))
return $this->_store[$key];
}
function set($key, &$obj) {
$this->_store[$key] =& $obj;
}
}

分享:《PHP設(shè)計(jì)模式介紹》第三章 工廠模式
在面向?qū)ο缶幊讨? 最通常的方法是一個(gè)new操作符產(chǎn)生一個(gè)對(duì)象實(shí)例,new操作符就是用來構(gòu)造對(duì)象實(shí)例的。但是在一些情況下, new操作符直接生成對(duì)象會(huì)帶來一些問題。舉例來說, 許多類型對(duì)象的創(chuàng)造需

來源:模板無憂//所屬分類:PHP教程/更新時(shí)間:2008-08-22
相關(guān)PHP教程