《PHP設(shè)計(jì)模式介紹》第五章 注冊(cè)模式(3)_PHP教程
推薦:《PHP設(shè)計(jì)模式介紹》第四章 單件模式幾乎所有面向?qū)ο蟮某绦蛑�,總有一兩個(gè)資源被創(chuàng)建出來(lái),在程序應(yīng)用中持續(xù)被共享使用。例如,這樣的一個(gè)資源,在一個(gè)電子商務(wù)程序的數(shù)據(jù)庫(kù)連接中使用:這個(gè)連接在應(yīng)用程序啟動(dòng)時(shí)初始化,程序于是
initRegistry()方法包含一個(gè)初始化為數(shù)組的靜態(tài)變量。這個(gè)靜態(tài)變量通過(guò)引用返回。在構(gòu)造函數(shù)中$_store實(shí)例變量被賦于通過(guò)initRegistry()函數(shù)返回的引用——即靜態(tài)數(shù)組。好!一個(gè)PHP4的類(lèi)靜態(tài)變量產(chǎn)生了。
使用類(lèi)靜態(tài)變量的實(shí)現(xiàn):
PHP5中,沒(méi)有必要自己實(shí)現(xiàn)類(lèi)靜態(tài)變量,因?yàn)镻HP5直接支持類(lèi)靜態(tài)變量。因此,PHP5簡(jiǎn)化了實(shí)現(xiàn)。而且,PHP5中引用、對(duì)象不再有PHP4中的意義,但是assertReference() 處理了這種差別,如果兩個(gè)變量指向同一個(gè)對(duì)象句柄也可以通過(guò)測(cè)試。
以下是為PHP5改寫(xiě)的類(lèi)似的Registry測(cè)試用例。
| // PHP5 class RegistryMonoStatePHP5TestCase extends UnitTestCase { function testRegistryMonoState() { $this->assertCopy( $reg = new RegistryMonoState ,$reg2 = new RegistryMonoState); $this->assertFalse($reg->isValid(‘key’)); $this->assertNull($reg->get(‘key’)); $test_value = new TestObj; $reg->set(‘key’, $test_value); $this->assertReference($test_value, $reg2->get(‘key’)); } } |
以下是PHP5版本的使用靜態(tài)類(lèi)變量的Registry類(lèi)。
| class RegistryMonoState { protected static $store = array(); function isValid($key) { return array_key_exists($key, RegistryMonoState::$store); } function get($key) { if (array_key_exists($key, RegistryMonoState::$store)) return RegistryMonoState::$store[$key]; } function set($key, $obj) { RegistryMonoState::$store[$key] = $obj; } } |
PHP5中用這種方式編碼Registry類(lèi)的一個(gè)有趣的效果是你可以用相同的代碼使用實(shí)例或者靜態(tài)方法。以下是證明僅僅使用靜態(tài)方法的測(cè)試用例。
| class RegistryMonoStatePHP5TestCase extends UnitTestCase { function testRegistryMonoState() { /*...*/ } function testRegistryMonoStateStaticCalls() { $this->assertFalse(RegistryMonoState::isValid(‘key’)); $this->assertNull(RegistryMonoState::get(‘key’)); $test_value = new TestObj; RegistryMonoState::set(‘key’, $test_value); $this->assertIdentical($test_value, RegistryMonoState::get(‘key’)); } |
現(xiàn)在你已經(jīng)看到在PHP5中的靜態(tài)調(diào)用接口,下面讓我們?cè)赑HP4中實(shí)現(xiàn)相同的接口。在前面的PHP4“靜態(tài)類(lèi)變量”部分,實(shí)現(xiàn)需要使用“函數(shù)靜態(tài)變量返回引用”來(lái)跟蹤。PHP4版本的靜態(tài)調(diào)用接口測(cè)試與PHP5版本的測(cè)試類(lèi)似。
| // PHP4 class RegistryStaticPHP4TestCase extends UnitTestCase { function testRegistryStatic() { $this->assertFalse(RegistryStatic::isValid(‘key’)); $this->assertNull(RegistryStatic::get(‘key’)); $test_value = ‘something’; RegistryStatic::set(‘key’, $test_value); $this->assertReference($test_value, RegistryStatic::get(‘key’)); } } |
以下是符合測(cè)試要求的代碼實(shí)現(xiàn)。
| class RegistryStatic { function &_getRegistry() { static $store = array(); return $store; } function isValid($key) { $store =& RegistryStatic::_getRegistry(); return array_key_exists($key, $store); } function &get($key) { $store =& RegistryStatic::_getRegistry(); if (array_key_exists($key, $store)) return $store[$key]; } function set($key, &$obj) { $store =& RegistryStatic::_getRegistry(); $store[$key] =& $obj; } } |
這個(gè)實(shí)現(xiàn)方法的重點(diǎn)是getRegistry()方法返回一個(gè)對(duì)靜態(tài)數(shù)組的引用。
$store =& RegistryStatic::_getRegistry();這一行,在隨后的函數(shù)中把變量$store通過(guò)引用賦給靜態(tài)數(shù)組,允許所有的函數(shù)可以靜態(tài)訪問(wèn)數(shù)組,允許所有的方法可以被靜態(tài)調(diào)用。
也可以不使用PHP4“靜態(tài)類(lèi)變量跟蹤”達(dá)到相同的效果:將原先的基于單件模式的Registry類(lèi)與一個(gè)包裝類(lèi)結(jié)合以達(dá)到允許靜態(tài)調(diào)用。這個(gè)類(lèi)與testRegistryStatic()有相同的測(cè)試代碼,但是他的實(shí)現(xiàn)如下所示:
| class RegistryStatic { function isValid($key) { $reg =& Registry::getInstance(); return $reg->isValid($key); } function &get($key) { $reg =& Registry::getInstance(); return $reg->get($key); } function set($key, &$obj) { $reg =& Registry::getInstance(); $reg->set($key, $obj); } } |
結(jié)論:
雖然注冊(cè)模式簡(jiǎn)化了對(duì)大量對(duì)象的訪問(wèn),但是仍然有許多問(wèn)題——與全局變量聯(lián)合。你需要確定要求的屬性Key在訪問(wèn)之已經(jīng)被初始化了,而且設(shè)置屬性的方法可以全局訪問(wèn),你的對(duì)象仍然可能在你的代碼的其他部分出乎意料的被替換掉。顯然,全局?jǐn)?shù)據(jù)非常有好處,方便,但是你需要時(shí)刻記住任何全局?jǐn)?shù)據(jù)都是有一些不安全的。
內(nèi)嵌的Registry模式
除了單獨(dú)使用注冊(cè)模式——如本章所示,Registry模式與其他對(duì)象結(jié)合時(shí)功能也是非常強(qiáng)大。例如:當(dāng)對(duì)象的創(chuàng)建代價(jià)非常昂貴(例如需要查詢(xún)大量數(shù)據(jù)庫(kù)來(lái)初始化對(duì)象)時(shí),而且對(duì)象在這個(gè)應(yīng)用中被使用一次或多次,如果這樣,你能創(chuàng)建一個(gè)結(jié)合了工作模式 (見(jiàn)第三章) 和注冊(cè)模式 的“Finder”類(lèi)以獲得已經(jīng)創(chuàng)建的對(duì)象的緩存而不用再次創(chuàng)建他們?
以下是一個(gè)Contact類(lèi),AddressBook類(lèi)是工廠類(lèi)。
| class AddressBook { function &findById($id) { return new Contact($id); } } class Contact { function Contact($id) { // expensive queries to create object using $id } // ... other methods } |
你可以在AddressBook類(lèi)中插入Registry模式來(lái)提供緩存。代碼可以如下所示:
| class AddressBook { var $registry; function AddressBook() { $this->registry =& Registry::getInstance(); } function &findById($id) { if (!$this->registry->isValid($id)) { $this->registry->set($id, new Contact($id)); } return $this->registry->get($id); } } |
AddressBook類(lèi)的構(gòu)造函數(shù)將registry綁定到一個(gè)實(shí)例變量。當(dāng)創(chuàng)建了一個(gè)特定的ID并被findById()方法調(diào)用時(shí),Registry被檢查以確定對(duì)象是否已經(jīng)被緩存。如果沒(méi)有,將創(chuàng)建一個(gè)新的對(duì)象并存儲(chǔ)在Registry中。被調(diào)用的對(duì)象將通過(guò)函數(shù)從Registry中取出并被返回。
分享:《PHP設(shè)計(jì)模式介紹》第三章 工廠模式在面向?qū)ο缶幊讨? 最通常的方法是一個(gè)new操作符產(chǎn)生一個(gè)對(duì)象實(shí)例,new操作符就是用來(lái)構(gòu)造對(duì)象實(shí)例的。但是在一些情況下, new操作符直接生成對(duì)象會(huì)帶來(lái)一些問(wèn)題。舉例來(lái)說(shuō), 許多類(lèi)型對(duì)象的創(chuàng)造需
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪問(wèn)控制的和運(yùn)算符優(yōu)先級(jí)介紹
- 關(guān)于PHP語(yǔ)言構(gòu)造器介紹
- php/js獲取客戶(hù)端mac地址的實(shí)現(xiàn)代碼
- php5.5新數(shù)組函數(shù)array_column使用
- PHP preg_match的匹配多國(guó)語(yǔ)言的技巧
- php 中序列化和json使用介紹
- php采集文章中的圖片獲取替換到本地
PHP教程Rss訂閱編程教程搜索
PHP教程推薦
- 使用PHP實(shí)現(xiàn)蜘蛛訪問(wèn)日志統(tǒng)計(jì)
- 一些PHP學(xué)習(xí)過(guò)程中的心得和經(jīng)驗(yàn)
- 三個(gè)準(zhǔn)則教你成為PHP編程高手
- 解析PHP如何透過(guò)ODBC來(lái)存取數(shù)據(jù)庫(kù)
- php防止sql注入的函數(shù)介紹
- php中使用$_REQUEST需要注意的一個(gè)問(wèn)題
- Zend的MVC機(jī)制使用分析(一)
- 解析PHP正則表達(dá)式的幾則使用技巧
- PHP使用zlib擴(kuò)展實(shí)現(xiàn)頁(yè)面GZIP壓縮輸出
- PHP打印一個(gè)三角形
- 相關(guān)鏈接:
- 教程說(shuō)明:
PHP教程-《PHP設(shè)計(jì)模式介紹》第五章 注冊(cè)模式(3)
。