PHP程序员站--PHP编程开发平台
 当前位置:主页 >> PHP高级编程 >> 高级应用 >> 

PHP设计模式介绍 第八章 迭代器模式

PHP设计模式介绍 第八章 迭代器模式

来源:互联网  作者:  发布时间:2010-05-21
类中的面向对象编程封装应用逻辑。类,就是实例化的对象,每个

你的集合类必须提供 Factory(参见第 3 章)来创建迭代器的实例。

 

迭代器类定义 first() 转到集合开始的接口,

next() 移到序列中的下一个项作为你的循环,currentItem() 从集合检索当前的项作为你的循环, isDone() 用于指出你在整个集合中循环结束的时间。

在“示例代码”部分,LibraryGofIterator 类是一个直接实现 GoF 迭代器设计模式的示例。

 


样本代码

在 Library 内实现 GoF 迭代器模式的第一步是为新的具体迭代器写一个新的测试用例。因为每一种测试方法都将操纵包含 Media 实例的 Library,你可以清空 UnitTestCase::setUp() 方法,从而在每种测试的已知状态下将变量填充到 Library 中。

首先,将 Library::getIterator()  方法作为LibraryGofIterator 类的 一个 Factory 实例。

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’);
}
}

实现:

class  Library  {
//  ...
function  getIterator()  {
return  new  LibraryGofIterator($this->collection);
}
}

getIterator() 方法将 Library 的 $collection 传递给新的具体迭代器结构。这一方法有两个重要的实现:每个迭代器都是独立的,因此可以同时操作多个迭代器。另外,迭代器在数组上的操作是当迭代器被请求时才执行的。如果之后将另一个项添加到集合中,你必须请求另一个迭代器来显示它(至少是在该实现中)。让我们通过将声明添加到    TestGetGofIterator() 方法以匹配迭代器设计模式,继续对测试进行加强。

如果你已经对整个集合进行遍历,则 isDone() 方法只应该为 true。如果 iterator 刚刚创建,则 isDone() 显然返回 false,从而指出集合可以遍历。

 

class  IteratorTestCase  extends  UnitTestCase  {
function  setup()  {  /*  ...  */  }
function  TestGetGofIterator()  {
$this->assertIsA($it  =  $this->lib->getIterator()
,’LibraryGofIterator’);
$this->assertFalse($it->isdone());
}
}

与 TDD 一样,尽可能实现最简单的代码来满足你的测试用例:

class  LibraryGofIterator  {
function  isDone()  {
return  false;
}
}

因此,在第一个迭代器间,应该发生什么呢? currentItem() 应该返回第一个 Media 对象,这个对象是在 IteratorTestCase::setUp() 方法中添加的,isDone() 应该继续为 false,因为另两个项仍然等待遍历。

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 接收了构造函数中的 $collection, 这一点非常重要(参见上面的 Library 最小化实现)并从 currentItem() 方法返回 current() 项。

class  LibraryGofIterator  {
protected  $collection;
function  __construct($collection)  {
$this->collection  =  $collection;
}
function  currentItem()  {
return  current($this->collection);
}
function  isDone()  {
return  false;
}
}


在下一个迭代会出现什么? next() 方法应该更改currentItem() 方法返回的项。下面的测试捕获了所期望的行为:

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 的数组函数之上,在数组上使用 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() 方法必须返回 之外,第三个迭代看起来很像其他的迭代。你还希望 next() 能够成功移到下一个迭代:

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());
}
}

对 next() 和 isDone() 方法稍加修改,所有的测试都通过了。代码如下:

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);
}
}

迭代器测试用例只存在一个问题:它没有反映迭代器的典型用法。是的,它测试了迭代器模式的所有功能,但应用程序需要采用更简单的方法来使用迭代器。因此,下一步是使用更贴实际的代码来编写测试。


延伸阅读:
从魔兽看PHP设计模式
《PHP设计模式介绍》导言
PHP设计模式介绍 第一章 编程惯用法
PHP设计模式介绍 第二章 值对象模式
PHP设计模式介绍 第三章 工厂模式
PHP设计模式介绍 第四章 单件模式
PHP设计模式介绍 第五章 注册模式
PHP设计模式介绍 第六章 伪对象模式
PHP设计模式介绍 第七章 策略模式

最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号