WebjxCom提示:php教程:php设计模式介绍之迭代器模式.
LibraryGofIterator接收了构造函数中的$collection
,这一点非常重要(参见上面的Library最小化实现)并从currentItem()方法返回current()项
。 classLibraryGofIterator{
protected$collection;
function__construct($collection){
$this->collection=$collection;
}
functioncurrentItem(){
returncurrent($this->collection);
}
functionisDone(){
returnfalse;
}
}
在下一个迭代会出现什么?next()方法应该更改currentItem()方法返回的项
。下面的测试捕获了所期望的行为:
classIteratorTestCaseextendsUnitTestCase{
functionsetup(){/*...*/}
functionTestGetGofIterator(){
$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的数组函数之上
,在数组上使用next():
classLibraryGofIterator{
protected$collection;
function__construct($collection){
$this->collection=$collection;
}
functioncurrentItem(){
returncurrent($this->collection);
}
functionnext(){
returnnext($this->collection);
}
functionisDone(){
returnfalse;
}
}
除了isDone()方法必须返回之外,第三个迭代看起来很像其他的迭代。你还希望next()能够成功移到下一个迭代:
classIteratorTestCaseextendsUnitTestCase{
functionsetup(){/*...*/}
functionTestGetGofIterator(){
$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());
}
}
对next()和isDone()方法稍加修改,所有的测试都通过了。代码如下:
classLibraryGofIterator{
protected$collection;
function__construct($collection){
$this->collection=$collection;
}
functionfirst(){
reset($this->collection);
}
functionnext(){
return(false!==next($this->collection));
}
functionisDone(){
return(false===current($this->collection));
}
functioncurrentItem(){
returncurrent($this->collection);
}
}
迭代器测试用例只存在一个问题:它没有反映迭代器的典型用法。是的,它测试了迭代器模式的所有功能,但应用程序需要采用更简单的方法来使用迭代器。因此,下一步是使用更贴实际的代码来编写测试。
classIteratorTestCaseextendsUnitTestCase{
protected$lib;
functionsetup(){/*...*/}
functionTestGetGofIterator(){/*...*/}
functionTestGofIteratorUsage(){
$output=‘’;
for($it=$this->lib->getIterator();!$it->isDone();$it->next()){
$output.=$it->currentItem()->name;
}
$this->assertEqual(‘name1name2name3’,$output);
}
}
目前,迭代器的实现复制了某个数组(集合),并使用
PHP的内部指针来跟踪迭代。你还可以通过自己跟踪集合索引来实现迭代器。这需要Library中的一种新的accessor方法来通过关键字访问对象。
classLibrary{
//...
functionget($key){
if(array_key_exists($key,$this->collection)){
return$this->collection[$key];
}
}
}
同样,在Library::getIterator()方法中,你可能将$this(library本身)传递给构造程序,而不是将$this传递给集合(数组包含Media集合)。外部的迭代器然后只是内部地跟踪指针以了解它当前引用的是哪一个Library集合元素,并将使用构造行数中从引用到Library的传递来检索当前的对象。
classLibraryGofExternalIterator{
protected$key=0;
protected$collection;
function__construct($collection){
$this->collection=$collection;
}
functionfirst(){
$this->key=0;
}
functionnext(){
return(++$this->key<$this->collection->count());
}
functionisDone(){
return($this->key>=$this->collection->count());
}
functioncurrentItem(){
return$this->collection->get($this->key);
}
}
这一实现假设你的集合数组从0开始建立索引,并且是完全连续的。