The first step in implementing the GoF Iterator pattern within Library is to write a new test case for the new concrete Iterator. Since each test method will manipulate a Library filled with Media instances, you can employ the UnitTestCase::setUp() method to populate a variable with a Library in a known state for each test. Start by adding the Library::getIterator() method as a Factory for instances of the LibraryGofIterator class. class IteratorTestCase extends UnitTestCase { Here's the implementation: class Library { The getIterator() method passes the Library's $collectionto the constructor of the new concrete iterator. This technique has twoimportant implications: each iterator is independent, so multipleiterators can operate at the same time. Additionally, the iteratoroperates on the collection as it existed at the time theiterator was requested. If another item is added to the collection atany time later, you must request another iterator to display it (atleast in this implementation). Let's continue enhancing the test suite by adding assertions to the TestGetGofIterator() method to match the Iterator design pattern. The isDone() method should only be true if you've iterated over the entire collection. If the iterator's just been created, isDone() should obviously return false to indicate it's okay to iterate. class IteratorTestCase extends UnitTestCase { As usual with TDD, implement the simplest possible code that satisfies your test case: class LibraryGofIterator { So, what should happen during the first iteration?currentItem() should return the first Media object added in the IteratorTestCase::setUp() method and isDone() should continue to be false, since two additional items remain to be iterated over. class IteratorTestCase extends UnitTestCase { It's critical that LibraryGofIterator receives the $collection in the constructor (see the minimal implementation of Library above) and returns the current() item of that array from the currentItem()method. class LibraryGofIterator { What should happen in the next iteration? The next()method should change what item is returned by the currentItem() method. This next test captures that expected behavior: class IteratorTestCase extends UnitTestCase { Piggybacking again on PHP's array functions, use next() on the array: class LibraryGofIterator { The third iteration looks much like the others, except the isDone() method must return true. You also want next() to indicate success of moving to the next iteration: class IteratorTestCase extends UnitTestCase { With small modifications to the next() and isDone()methods, all of the tests pass Here's the code so far: class LibraryGofIterator { There's just one problem with the Iterator test case: it doesn't reflect how iterators are typically used. Yes, it tests all of the features of the Iterator pattern, but application code uses the Iterator in a much simpler way. So, the next step is to write a test using more realistic code. class IteratorTestCase extends UnitTestCase { So far, the implementation of Iterator copies an array (the collection) and uses PHP's internal pointer to track the iteration. You can also implement the Iterator by keeping track of the collection index by yourself. This requires a new accessor method in Library to fetch an object by key. class Library { Also, you'd pass $this (the library itself) to the constructor instead of $this->collection (the array containing the Media collection) in the Library::getIterator() method. The "external" iterator would then just track a pointer internally to know which element of the Library collection it's currently referencing, and would use the reference to the Library passed in the constructor to call the get() method to retrieve the current object. class LibraryGofExternalIterator { This implementation assumes your collection array is indexed starting with 0 and is completely sequential.
blog comments powered by Disqus |
|
|
|
|
|
|
|