Design Pattern: Iterator and Movie Collections

Design Pattern: Iterator and Movie Collections

Design Patterns in life and Ruby — gain an intuitive understanding of OO design patterns by linking them with real-life examples.

 

The Iterator Pattern answers this question: What’s next?

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

In English, an iterator returns items from a collection one at a time until it has returned all items from the collection.

Let’s use the Iterator Pattern to build our movie collection.

Let’s pretend we have subscriptions for both Netflix and Amazon Prime. Our goal is to combine all the movies on Netflix and Amazon Prime to build our movie collection.

We can ask Netflix for a list of available movies. For simplicity sake, only three movies are listed.

 

We can also ask Amazon for a list of available movies.

 

With both lists, we are ready to build our movie collection combining the two.

Notice the way we loop through netflix_movies is different than the way we loop through amazon_movies. That is because netflix_movies is an array and amazon_movies is a hashmap from movie_id to movie.

In order to loop through netflix_movies and amazon_movies correctly, MovieCollection has to know netflix_movies is an array and amazon_movies is a hashmap.

This design is fine when there are only two movie subscriptions.

But now we want to subscribe to three more online movie subscriptions: Hulu, YouTube, and HBO. Their movie collection types are: array, array, and hashmap, respectively.

 

Including these three new subscriptions, our MovieCollection will look like this:

The get_all_movies method is fragile because it has to remember collection types for all movie vendors. A developer might accidentally change amazon_movies.each do |movie_id, movie| to amazon_movies.each do |movie|, and then the code is broken.

The method is also unscalable. As the list of subscriptions grows, it becomes less maintainable.

 

Time to use Iterators

The complexity in the example comes from the fact that different movie vendors use different collection types for their movies. Some use arrays, others use hashmaps, and the get_all_movies metod has to keep track of who uses what.

It would be great if the get_all_movies method could ignore collection types.

After all, all it cares about is getting and adding the next movie to movies until there are no more movies left in the current list.

Something like: while movie_iterator.has_next? { all_movies << movie_iterator.next } is what we want.

With this in mind, we can rewrite the method to:

Obviously, it can be further simplified to:

 

We can also pass the list of movie_iterators into initialize, so we can change our movie subscriptions without having to update the MovieCollection class.

 

Time to create Iterators

The only thing left is to create movie_iterators.
Since there are two types of collections, array and hashmap, we need two types of iterators.

An ArrayIterator:

 

And a HashIterator:

And we can use them like this:

The most important thing is that both ArrayIterator and HashIterator use the same interface:

  • an iterator is created by passing a collection into initialize
  • an iterator responds to has_next? and next.

The unified iterator interface allows clients who use iterators, get_all_movies in our case, to be ignorant about the type of the collection. Clients can iterate through a collection with has_next? and next without knowing the structure of the collection.

Woohoo, that’s exactly the definition of the Iterator Pattern!

 

Takeaways

The Iterator Pattern provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

 

With our movie collection, we are ready to binge watch 📺 📺 📺.

 

Next time we will talk about group chats.

Don’t forget to subscribe so you won’t miss the next post! 🙃


Enjoyed the article?

My best content on Software Design, Rails, and Career in Dev. Delivered weekly.

Unsubscribe at anytime. I'll never spam you. Powered by ConvertKit

Leave a Comment