《PHP設(shè)計(jì)模式介紹》第八章 迭代器模式(2)_PHP教程
推薦:《PHP設(shè)計(jì)模式介紹》第七章 策略模式在編寫(xiě)面向?qū)ο蟮拇a的時(shí),有些時(shí)候你需要一個(gè)能夠自己根據(jù)不同的條件來(lái)引入不同的操作對(duì)象實(shí)例。例如,一個(gè)菜單功能能夠根據(jù)用戶(hù)的“皮膚”首選項(xiàng)來(lái)決定是否采用水平的還是垂直的排
你的集合類(lèi)必須提供 Factory(參見(jiàn)第 3 章)來(lái)創(chuàng)建迭代器的實(shí)例。
迭代器類(lèi)定義 first() 轉(zhuǎn)到集合開(kāi)始的接口,
next() 移到序列中的下一個(gè)項(xiàng)作為你的循環(huán),currentItem() 從集合檢索當(dāng)前的項(xiàng)作為你的循環(huán), isDone() 用于指出你在整個(gè)集合中循環(huán)結(jié)束的時(shí)間。
在“示例代碼”部分,LibraryGofIterator 類(lèi)是一個(gè)直接實(shí)現(xiàn) GoF 迭代器設(shè)計(jì)模式的示例。
樣本代碼
在 Library 內(nèi)實(shí)現(xiàn) GoF 迭代器模式的第一步是為新的具體迭代器寫(xiě)一個(gè)新的測(cè)試用例。因?yàn)槊恳环N測(cè)試方法都將操縱包含 Media 實(shí)例的 Library,你可以清空 UnitTestCase::setUp() 方法,從而在每種測(cè)試的已知狀態(tài)下將變量填充到 Library 中。
首先,將 Library::getIterator() 方法作為L(zhǎng)ibraryGofIterator 類(lèi)的 一個(gè) Factory 實(shí)例。
| class IteratorTestCase extends UnitTestCase { protected $lib; function setup() { $this->lib = new Library; $this->lib->add(new Media(‘name1’, 2000)); $this->lib->add(new Media(‘name2’, 2002)); $this->lib->add(new Media(‘name3’, 2001)); } function TestGetGofIterator() { $this->assertIsA($it = $this->lib->getIterator() ,’LibraryGofIterator’); } } |
實(shí)現(xiàn):
| class Library { // ... function getIterator() { return new LibraryGofIterator($this->collection); } } |
getIterator() 方法將 Library 的 $collection 傳遞給新的具體迭代器結(jié)構(gòu)。這一方法有兩個(gè)重要的實(shí)現(xiàn):每個(gè)迭代器都是獨(dú)立的,因此可以同時(shí)操作多個(gè)迭代器。另外,迭代器在數(shù)組上的操作是當(dāng)?shù)鞅徽?qǐng)求時(shí)才執(zhí)行的。如果之后將另一個(gè)項(xiàng)添加到集合中,你必須請(qǐng)求另一個(gè)迭代器來(lái)顯示它(至少是在該實(shí)現(xiàn)中)。讓我們通過(guò)將聲明添加到 TestGetGofIterator() 方法以匹配迭代器設(shè)計(jì)模式,繼續(xù)對(duì)測(cè)試進(jìn)行加強(qiáng)。
如果你已經(jīng)對(duì)整個(gè)集合進(jìn)行遍歷,則 isDone() 方法只應(yīng)該為 true。如果 iterator 剛剛創(chuàng)建,則 isDone() 顯然返回 false,從而指出集合可以遍歷。
| class IteratorTestCase extends UnitTestCase { function setup() { /* ... */ } function TestGetGofIterator() { $this->assertIsA($it = $this->lib->getIterator() ,’LibraryGofIterator’); $this->assertFalse($it->isdone()); } } |
與 TDD 一樣,盡可能實(shí)現(xiàn)最簡(jiǎn)單的代碼來(lái)滿(mǎn)足你的測(cè)試用例:
| class LibraryGofIterator { function isDone() { return false; } } |
因此,在第一個(gè)迭代器間,應(yīng)該發(fā)生什么呢? currentItem() 應(yīng)該返回第一個(gè) Media 對(duì)象,這個(gè)對(duì)象是在 IteratorTestCase::setUp() 方法中添加的,isDone() 應(yīng)該繼續(xù)為 false,因?yàn)榱韮蓚(gè)項(xiàng)仍然等待遍歷。
| class IteratorTestCase extends UnitTestCase { function setup() { /* ... */ } function TestGetGofIterator() { $this->assertIsA($it = $this->lib->getIterator() ,’LibraryGofIterator’); $this->assertFalse($it->isdone()); $this->assertIsA($first = $it->currentItem(), ‘Media’); $this->assertEqual(‘name1’, $first->name); $this->assertFalse($it->isdone()); } } |
LibraryGofIterator 接收了構(gòu)造函數(shù)中的 $collection, 這一點(diǎn)非常重要(參見(jiàn)上面的 Library 最小化實(shí)現(xiàn))并從 currentItem 方法返回 current() 項(xiàng)。
| class LibraryGofIterator { protected $collection; function __construct($collection) { $this->collection = $collection; } function currentItem() { return current($this->collection); } function isDone() { return false; } } |
在下一個(gè)迭代會(huì)出現(xiàn)什么? next() 方法應(yīng)該更改currentItem() 方法返回的項(xiàng)。下面的測(cè)試捕獲了所期望的行為:
| class IteratorTestCase extends UnitTestCase { function setup() { /* ... */ } function TestGetGofIterator() { $this->assertIsA($it = $this->lib->getIterator(), ‘LibraryGofIterator’); $this->assertFalse($it->isdone()); $this->assertIsA($first = $it->currentItem(), ‘Media’); $this->assertEqual(‘name1’, $first->name); $this->assertFalse($it->isdone()); $this->assertTrue($it->next()); $this->assertIsA($second = $it->currentItem(), ‘Media’); $this->assertEqual(‘name2’, $second->name); $this->assertFalse($it->isdone()); } } |
重新建立在 PHP 的數(shù)組函數(shù)之上,在數(shù)組上使用 next():
| class LibraryGofIterator { protected $collection; function __construct($collection) { $this->collection = $collection; } function currentItem() { return current($this->collection); } function next() { return next($this->collection); } function isDone() { return false; } } |
除了 isDone() 方法必須返回 之外,第三個(gè)迭代看起來(lái)很像其他的迭代。你還希望 next() 能夠成功移到下一個(gè)迭代:
| class IteratorTestCase extends UnitTestCase { function setup() { /* ... */ } function TestGetGofIterator() { $this->assertIsA($it = $this->lib->getIterator(), ‘LibraryGofIterator’); $this->assertFalse($it->isdone()); $this->assertIsA($first = $it->currentItem(), ‘Media’); $this->assertEqual(‘name1’, $first->name); $this->assertFalse($it->isdone()); $this->assertTrue($it->next()); $this->assertIsA($second = $it->currentItem(), ‘Media’); $this->assertEqual(‘name2’, $second->name); $this->assertFalse($it->isdone()); $this->assertTrue($it->next()); $this->assertIsA($third = $it->currentItem(), ‘Media’); $this->assertEqual(‘name3’, $third->name); $this->assertFalse($it->next()); $this->assertTrue($it->isdone()); } } |
對(duì) next() 和 isDone() 方法稍加修改,所有的測(cè)試都通過(guò)了。代碼如下:
| class LibraryGofIterator { protected $collection; function __construct($collection) { $this->collection = $collection; } function first() { reset($this->collection); } function next() { return (false !== next($this->collection)); } function isDone() { return (false === current($this->collection)); } function currentItem() { return current($this->collection); } } |
迭代器測(cè)試用例只存在一個(gè)問(wèn)題:它沒(méi)有反映迭代器的典型用法。是的,它測(cè)試了迭代器模式的所有功能,但應(yīng)用程序需要采用更簡(jiǎn)單的方法來(lái)使用迭代器。因此,下一步是使用更貼實(shí)際的代碼來(lái)編寫(xiě)測(cè)試。
分享:《PHP設(shè)計(jì)模式介紹》第六章 偽對(duì)象模式面向?qū)ο蟮木幊讨载S富多彩,部分是由于對(duì)象間的相互聯(lián)系與作用。一個(gè)單一的對(duì)象就能封裝一個(gè)復(fù)雜的子系統(tǒng),使那些很復(fù)雜的操作能夠通過(guò)一些方法的調(diào)用而簡(jiǎn)化。(無(wú)所不在的數(shù)據(jù)庫(kù)連接就是這
- PHPNOW安裝Memcached擴(kuò)展方法詳解
- php記錄頁(yè)面代碼執(zhí)行時(shí)間
- PHP中獎(jiǎng)概率的抽獎(jiǎng)算法程序代碼
- apache設(shè)置靜態(tài)文件緩存方法介紹
- php對(duì)圖像的各種處理函數(shù)代碼小結(jié)
- PHP 關(guān)于訪(fǎng)問(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無(wú)限極分類(lèi)實(shí)現(xiàn)的兩種解決方法
- vim下高亮顯示php代碼
- 獲取php頁(yè)面執(zhí)行時(shí)間,數(shù)據(jù)庫(kù)讀寫(xiě)次數(shù),函數(shù)調(diào)用次數(shù)等(THINKphp)
- 淺談PHP 閉包特性在實(shí)際應(yīng)用中的問(wèn)題
- PHP flush()與ob_flush()的區(qū)別詳解
- php selectradio和checkbox默認(rèn)選擇的實(shí)現(xiàn)方法詳解
- 服務(wù)器變量 $_SERVER 的深入解析
- PHP preg_match的匹配多國(guó)語(yǔ)言的技巧
- 解析php中的escape函數(shù)
- 新手入門(mén):PHP網(wǎng)站開(kāi)發(fā)中常見(jiàn)問(wèn)題匯總
- 相關(guān)鏈接:
- 教程說(shuō)明:
PHP教程-《PHP設(shè)計(jì)模式介紹》第八章 迭代器模式(2)
。