Design Patterns - Iterator Pattern
Time for the next part in our series, the Iterator Pattern.
Let's start with the definition: "Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation."
Recently, we have received a request to add the notion of orders to our game. To this end, we created a new class, called TacticalMove which represents an order.
We have asked two of our junior developers to create a class for each faction which contains all orders for a given faction. After a while, they came up with the following implementations:
As you can see, our developers both took a different approach to the problem. One developer used a List to store the orders, while the other stored them in a fixed-size array.
If we want to create a WorldOrders class, which is able to display all orders of both factions, it would look a bit like this:
As you notice from the red colors, this initial approach has quite a few flaws.
First of all, we are programming against concrete implementations again, Eva and Legion.
We are also showing the internals of our classes to the outside world, since we have both collection representations showing.
And lastly, because we are pushing our internal storage through, we have two different kind of loops to display them. (Forget the foreach operator exists for a moment)
Let's fix this last part by introducing a new interface, called Iterator which has a HasNext() and Next() method, designed to iterate over a collection. When we have this interface, we need to create two new iterators for each implementation, one holding a List internally, while the other is storing the array.
The only thing we need to change to our Eva and Legion class now is to remove the GetOrders() method and replace it by the GetIterator() method.
Having done this change, allows us to go back to the WorldOrders and replace the two different loops by one identical loop.
We still need to pull out the concrete Eva and Legion classes however. Let's do this by introducing a new interface, called IFactionAI.
When we implement this new interface to our Eva and Legion classes, we have decoupled the WorldOrders class from them.
Taking a look at the class diagram, with the official names, we can now see WorldOrders is only working with Iterators and interfaces.
And that's the Iterator Pattern in action!
But wait, just like the Observer Pattern, we can create it ourselves, or we can use some of the features from the .NET Framework! Just like we used events earlier on, we can use IEnumerator and IEnumerable this time.
Refactoring our code to use these, results in the following classes remaining:
As you can see, there is no more LegionIterator either, since List provides a GetEnumerator method itself, which we simply call.
Time to test all this code we just wrote and try it out.
I've uploaded the solution again. Since this was quite a long article, have a look at the code, I've placed the code for each step in seperate folders so you can compare the changes between steps.
Some additional information on the Iterator Pattern: