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

《PHP設計模式介紹》第八章 迭代器模式(3)_PHP教程

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

推薦:《PHP設計模式介紹》第七章 策略模式
在編寫面向?qū)ο蟮拇a的時,有些時候你需要一個能夠自己根據(jù)不同的條件來引入不同的操作對象實例。例如,一個菜單功能能夠根據(jù)用戶的“皮膚”首選項來決定是否采用水平的還是垂直的排

class IteratorTestCase extends UnitTestCase {
protected $lib;
function setup() { /* ... */ }
function TestGetGofIterator() { /* ... */ }
function TestGofIteratorUsage() {
$output = ‘’;
for ($it=$this->lib->getIterator(); !$it->isDone(); $it->next()){
$output .= $it->currentItem()->name;
}
$this->assertEqual(‘name1name2name3’, $output);
}
}

目前,迭代器的實現(xiàn)復制了某個數(shù)組(集合),并使用 PHP 的內(nèi)部指針來跟蹤迭代。你還可以通過自己跟蹤集合索引來實現(xiàn)迭代器。這需要 Library 中的一種新的 accessor 方法來通過關鍵字訪問對象。

class Library {
// ...
function get($key) {
if (array_key_exists($key, $this->collection)) {
return $this->collection[$key];
}
}
}


同樣,在 Library::getIterator() 方法中,你可能將 $this(library 本身)傳遞給構造程序,而不是將 $this 傳遞給集合(數(shù)組包含Media 集合)。外部的迭代器然后只是內(nèi)部地跟蹤指針以了解它當前引用的是哪一個 Library 集合元素,并將使用構造行數(shù)中從引用到 Library 的傳遞來檢索當前的對象。

class LibraryGofExternalIterator {
protected $key = 0;
protected $collection;
function __construct($collection) {
$this->collection = $collection;
}
function first() {
$this->key=0;
}
function next() {
return ( $this->key < $this->collection->count());
}
function isDone() {
return ($this->key >= $this->collection->count());
}
function currentItem() {
return $this->collection->get($this->key);
}
}

這一實現(xiàn)假設你的集合數(shù)組從 0 開始建立索引,并且是完全連續(xù)的。

不同的迭代器 API

雖然前面的代碼是 GoF 所述迭代器模式的完整實現(xiàn),你還可能會發(fā)現(xiàn)四種方法的 API 有一點臃腫。如果是,你可以將 collapse next(), currentItem(), 和 isDone() 都并入 next() 中,用來從集合中返回本項或下一項,或者如果整個集合被遍歷過了,則返回 false。這是一個測試不同 API 的代碼:

class IteratorTestCase extends UnitTestCase {
// ...
function TestMediaIteratorUsage() {
$this->assertIsA(
$it = $this->lib->getIterator(‘media’)
,’LibraryIterator’);
$output = ‘’;
while ($item = $it->next()) {
$output .= $item->name;
}
$this->assertEqual(‘name1name2name3’, $output);
}
}

在上述代碼中,注意簡化的循環(huán)控制結構。 next() 返回對象或者false,允許你在 while 循環(huán)條件中執(zhí)行分配。下面的一些示例檢驗使用較小接口的不同迭代器模式。為了方便,將 Library::getIterator() 方法更改為參數(shù)化的 Factory,以便你可以從單一方法中獲取四種的方法迭代器或兩種方法的迭代器(next() 和 reset())。

class Library {
// ...
function getIterator($type=false) {
switch (strtolower($type)) {
case ‘media’:
$iterator_class = ‘LibraryIterator’;
break;
default:
$iterator_class = ‘LibraryGofIterator’;
}
return new $iterator_class($this->collection);
}
}

這里面的 Library::getIterator() 現(xiàn)在接受一個參數(shù)以選擇返回什么樣的迭代器。缺省為 LibraryGofIterator(因此現(xiàn)有的測試仍然能夠通過)。將字符串媒體傳遞給所創(chuàng)建的方法,并返回 LibraryIterator。這是一些實現(xiàn) LibraryIterator 的代碼:

class LibraryIterator {
protected $collection;
function __construct($collection) {
$this->collection = $collection;
}
function next() {
return next($this->collection);
}
}


請注意調(diào)試結果的紅色標記!什么導致發(fā)生錯誤“Equal expectation fails at character 4 with name1name2name3 and name2name3”?不知何故,跳過了第一次迭代 - 這是 bug。要修訂該錯誤,對于 next() 方法的第一次調(diào)用,返回 current()。

class LibraryIterator {
protected $collection;
protected $first=true;
function __construct($collection) {
$this->collection = $collection;
}
function next() {
if ($this->first) {
$this->first = false;
return current($this->collection);
}
return next($this->collection);
}
}

Presto! 綠色條和改進的 while 循環(huán)迭代器。

過濾迭代器

利用迭代器,你不僅僅可以顯示集合中的每一項。你還可以選擇顯示的項。修改 Library::getIterator() 來使用其它兩種迭代器類型。

class Library {
// ...
function getIterator($type=false) {
switch (strtolower($type)) {
case ‘media’:
$iterator_class = ‘LibraryIterator’;
break;
case ‘available’:
$iterator_class = ‘LibraryAvailableIterator’;
break;
case ‘released’:
$iterator_class = ‘LibraryReleasedIterator’;
break;
default:
$iterator_class = ‘LibraryGofIterator’;
}
return new $iterator_class($this->collection);
}
}


類 LibraryAvailableIterator 僅可以迭代狀態(tài)為“library”的項”(重新調(diào)用 checkOut() 方法,將狀態(tài)更改為“borrowed”)。

class IteratorTestCase extends UnitTestCase {
// ...
function TestAvailableIteratorUsage() {
$this->lib->add($dvd = new Media(‘test’, 1999));
$this->lib->add(new Media(‘name4’, 1999));
$this->assertIsA(
$it = $this->lib->getIterator(‘available’)
,’LibraryAvailableIterator’);
$output = ‘’;
while ($item = $it->next()) {
$output .= $item->name;
}
$this->assertEqual(‘name1name2name3testname4’, $output);
$dvd->checkOut(‘Jason’);
$it = $this->lib->getIterator(‘available’);
$output = ‘’;
while ($item = $it->next()) {
$output .= $item->name;
}
$this->assertEqual(‘name1name2name3name4’, $output);
}
}

該測試創(chuàng)建一個新的介質(zhì)實例,并將其存儲在變量 $dvd 中。突出顯示第一個 assertEqual() 聲明驗證利用 LibraryAvailableIterator 進行迭代時,存在一個新的項。接下來,測試使用 checkOut() 方法,并驗證新的項已丟失,不顯示。實現(xiàn)過濾得代碼非常類似于 LibraryIterator::next(),差別在于在返回項之前執(zhí)行過濾。如果當前項與過濾條件不匹配,則代碼返回 $this->next()。


class LibraryAvailableIterator {
protected $collection = array();
protected $first=true;
function __construct($collection) {
$this->collection = $collection;
}
function next() {
if ($this->first) {
$this->first = false;
$ret = current($this->collection);
} else {
$ret = next($this->collection);
}
if ($ret && ‘library’ != $ret->status) {
return $this->next();
}
return $ret;
}
}
排序迭代器

迭代器不僅可以顯示全部或部分集合。而且,還可以按特定順序顯示集合。下面,創(chuàng)建一個按集合眾介質(zhì)的發(fā)布日期進行排序的迭代器。為了進行測試,請?zhí)砑幽承┤掌谠?setUp() 方法中添加的項之后的介質(zhì)實例。如果迭代器運行,則這些日期較后的項應該位于迭代操作的最前面。

class IteratorTestCase extends UnitTestCase {
// ...
function TestReleasedIteratorUsage() {
$this->lib->add(new Media(‘second’, 1999));
$this->lib->add(new Media(‘first’, 1989));
$this->assertIsA(
$it = $this->lib->getIterator(‘released’)
,’LibraryReleasedIterator’);
$output = array();
while ($item = $it->next()) {
$output[] = $item->name .’-’. $item->year;
}
$this->assertEqual(
‘first-1989 second-1999 name1-2000 name3-2001 name2-2002’
,implode(‘ ‘,$output));
}
}

該測試使用的項在每個迭代中略有不同:并不僅僅是在字符串值后添加 $name,而是,字符串同時具有 $name 和 $year 屬性,這些屬性隨后將被添加到 $output 數(shù)組。LibraryReleasedIterator 的實現(xiàn)與 LibraryIterator 非常類似,除了 constuctor 中的一行語句:

class LibraryReleasedIterator extends LibraryIterator {
function __construct($collection) {
usort($collection, create_function(‘$a,$b’,’ return ($a->year - $b->year);’));
$this->collection = $collection;
}
}

用粗體表示的這一行將 $collection 數(shù)組排在迭代之前。你可以通過簡單地繼承 LibraryIterator 類,來避免復制該類的其它所有代碼�?梢允褂猛獠康鱽韺崿F(xiàn)相同的排序迭代嗎?是的,但是你必須注意完成它的訣竅。

分享:《PHP設計模式介紹》第六章 偽對象模式
面向?qū)ο蟮木幊讨载S富多彩,部分是由于對象間的相互聯(lián)系與作用。一個單一的對象就能封裝一個復雜的子系統(tǒng),使那些很復雜的操作能夠通過一些方法的調(diào)用而簡化。(無所不在的數(shù)據(jù)庫連接就是這

來源:模板無憂//所屬分類:PHP教程/更新時間:2008-08-22
相關PHP教程