排序迭代器
迭代器不仅可以显示全部或部分集合。而且,还可以按特定顺序显示集合。下面,创建一个按集合众介质的发布日期进行排序的迭代器。为了进行测试,请添加某些日期在 setUp() 方法中添加的项之后的介质实例。如果迭代器运行,则这些日期较后的项应该位于迭代操作的最前面。
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 数组。LibraryReleasedIterator 的实现与 LibraryIterator 非常类似,除了 constuctor 中的一行语句:
class LibraryReleasedIterator extends LibraryIterator {function __construct($collection) {usort($collection, create_function(‘$a,$b’,’ return ($a->year - $b->year);’));$this->collection = $collection;}}
用粗体表示的这一行将 $collection 数组排在迭代之前。你可以通过简单地继承 LibraryIterator 类,来避免复制该类的其它所有代码。可以使用外部迭代器来实现相同的排序迭代吗?是的,但是你必须注意完成它的诀窍。
class LibraryReleasedExternalIterator {protected $collection;protected $sorted_keys;protected $key=-1;function __construct($collection) {$this->collection = $collection;$sort_funct = create_function(‘$a,$b,$c=false’,‘static $collection;if ($c) {$collection = $c;return;}return ($collection->get($a)->year -$collection->get($b)->year);’);$sort_funct(null,null,$this->collection);$this->sorted_keys = $this->collection->keys();usort($this->sorted_keys, $sort_funct);}function next() {if (++$this->key >= $this->collection->count()) {return false;} else {return $this->collection->get($this->sorted_keys[$this->key]);}}}
其中,关键是创建用于排序的实用程序函数。排序函数必须能够访问集合,以便可以获取对照成员。然而,因为 gener- ated 函数在 usort() 中使用,没有将集合作为其它参数传递的选项。相反,你可以利用上述代码块中显示的诀窍,在利用 usort() 调用函数之前,将引用存储在函数中内部的集合中。排序的项是集合的关键字列表。当 usort() 完成时,关键字会按照集合中每个对象的 year 属性的顺序进行排序。在 next() 方法中,可以通过 get() 方法访问集合中的对象,而不是间接通过 $sorted_keys 映射。如果重新调用外部版本的 GoF 风格的迭代器,则不连续的数组或关键字中的字符串可能会有问题。可以使用针对 sim- ple 外部迭代器的相同诀窍,来减少关键字顺序不连贯的问题。