Iterator Design Pattern - Java
History Coding Kata
All Web Browsers keep history of websites a user is visiting. And they also provide facility to go back and forth by clicking left or right arrows.
Lets write a program to simulate this feature. Program should provide methods to store and remove website urls and also provide a mechanism to loop through and print the history.
Program should be easy to maintain. Client code should not depend on the inner working details.
First Step
Write a program without using any design patterns. This is an important step. Wihout this step, if you directly jump to deisgn pattern then you will not know what problem the design pattern is solving, so do not skip this step
Example:
- Create a class
BrowseHistory - Use a List of Strings
List<String>data structure to store the urls - Provide
pushandpopmethods to store or remove urls from the list - Client program uses
pushandpopmethods ofBrowseHistoryclass to store or remove the urls from history - Client program uses a
for loopto irerate through the history
- Create a class
Disadvantages with above approach
- A change in data structure will affect the client code
- Ex: If we decide to use a fixed size array like
String[]instead ofList<String>thenfor loopbreaks, because looping throughString[]would require a different logic. This means a breaking change to client code.
Applying Iterator Design Patterrn
Overview of Implementation
Instead of the client program directly depending on the concrete implementation, we can use an interface to decouple the client code from internal details.
Lets say BrowseHistory is the class used by the client to store, retrieve and loop through the history of urls.
Client will ask the BrowseHistory to give an iterator, ex: createIterator() method and then uses the interface methods of the iterator object to iterate through the list. In future if we decide to use a different data structure then it will not break the client code because the client is using an interface which means not depending on implementation details.
Detail Steps
- Create an interface
// pseudo code
interface Iterator {
boolean hasNext() // tells if there are any more items in the list
void next() // advances the index
String current() // returns current item
}
In the above interface, client is expected to use
Stringtype for the urls.We can further remove this dependency by using
GenericsCreating a generic interface
// pseudo code
interface Iterator<T> {
boolean hasNext() // tells if there are any more items in the list
void next() // advances the index
T current() // returns current item
}
In the above interface, type is indicated by
T, and it is decided during run timeThis gives flexibility to client. Client can use
Stringor any other supported types. Client can ask for specific type of iterator. For ex:createStringIterator() // type is StringcreateCookieIterator() // type is Cookie- etc..
Depending on what the client asks for,
BrowseHistoywill provide that specific iterator to the clientThe way to iterate is same for any type, so no change in code on client needed for the actual iteration process.
Use an Inner Class ex:
class ListIteratorto implement the interface. This is because iterrator requires access to the history and using an inner class we can avoid exposing the history outside ofBrowseHistoryclass.If we change the implementation from
ListtoString[]then we need to update only theBrowseHistoryclass. Client code is not affected by this change, it is an implementation detail.
How to run the programs ?
Implement using List<String>
Clone GitHub repository
git@github.com:smarigowda/IteratePatternJava.git
Run the main program
Change the implementation to use Stting[] to prove that it does not affect client code
Clone GitHub repository
git@github.com:smarigowda/IteratePatternJava.git
Change branch
git checkout exercise-string-array
Run the main program
