上文:
样本代码
在 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());}}