我们回到本章的重点
,迭代器设计模式的实现
。下列UML类图显示了GoF迭代器模式与Media和Library类结合使用巩固示例的方法
。 ?你的集合类必须提供Factory(参见第3章)来创建迭代器的实例。
?迭代器类定义first()转到集合开始的接口
, next()移到序列中的下一个项作为你的循环,currentItem()从集合检索当前的项作为你的循环,isDone()用于指出你在整个集合中循环结束的时间。
在“示例代码”部分,LibraryGofIterator类是一个直接实现GoF迭代器设计模式的示例。
样本代码
在Library内实现GoF迭代器模式的第一步是为新的具体迭代器写一个新的测试用例。因为每一种测试方法都将操纵包含Media实例的Library,你可以清空UnitTestCase::setUp()方法,从而在每种测试的已知状态下将变量填充到Library中。
首先,将Library::getIterator()方法作为LibraryGofIterator类的一个Factory实例。
classIteratorTestCaseextendsUnitTestCase{
protected$lib;
functionsetup(){
$this->lib=newLibrary;
$this->lib->add(newMedia(‘name1’,2000));
$this->lib->add(newMedia(‘name2’,2002));
$this->lib->add(newMedia(‘name3’,2001));
}
functionTestGetGofIterator(){
$this->assertIsA($it=$this->lib->getIterator()
,’LibraryGofIterator’);
}
}
实现:
classLibrary{
//...
functiongetIterator(){
returnnewLibraryGofIterator($this->collection);
}
}
getIterator()方法将Library的$collection传递给新的具体迭代器结构。这一方法有两个重要的实现:每个迭代器都是独立的,因此可以同时操作多个迭代器。另外,迭代器在数组上的操作是当迭代器被请求时才执行的。如果之后将另一个项添加到集合中,你必须请求另一个迭代器来显示它(至少是在该实现中)。让我们通过将声明添加到TestGetGofIterator()方法以匹配迭代器设计模式,继续对测试进行加强。
如果你已经对整个集合进行遍历,则isDone()方法只应该为true。如果iterator刚刚创建,则isDone()显然返回false,从而指出集合可以遍历。
classIteratorTestCaseextendsUnitTestCase{
functionsetup(){/*...*/}
functionTestGetGofIterator(){
$this->assertIsA($it=$this->lib->getIterator()
,’LibraryGofIterator’);
$this->assertFalse($it->isdone());
}
}
与TDD一样,尽可能实现最简单的代码来满足你的测试用例:
classLibraryGofIterator{
functionisDone(){
returnfalse;
}
}
因此,在第一个迭代器间,应该发生什么呢?currentItem()应该返回第一个Media对象,这个对象是在IteratorTestCase::setUp()方法中添加的,isDone()应该继续为false,因为另两个项仍然等待遍历。
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());
}
}