Understanding Design Patterns
This article is part of series in Understanding Design Patterns:
- Understanding Design Patterns - Simple Factory
- Understanding Design Patterns - Factory Method
- Understanding Design Patterns - Abstract Factory
- Understanding Design Patterns - Singleton
- Understanding Design Patterns - Observer
- Understanding Design Patterns - Command
- Understanding Design Patterns - Template Method
- Understanding Design Patterns - Strategy
- Understanding Design Patterns - Iterator
- Understanding Design Patterns - Composite
- Understanding Design Patterns - Decorator
- Understanding Design Patterns - State
- Understanding Design Patterns - Adapter
- Understanding Design Patterns - Facade
Provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
As a store manager, Eric’s job includes checking in products from each department. There are actually two departments in the store. One is called men's department, which holds products for men, and the other one is called women's department for women's products. Each department stores their products using different storage structures (data structures).
The Men's department stores products using array structure:
The women's department stores products using SqlStack structure:
So for Eric, the store manager, the code would look like this. Pay attention to function checkIn():
Depending on the data structure the department uses, we need to use different way to iterator the storage. This will quickly introduce a problem. Imagine if the women's department decides to use an array to store products too. We will not only need to update the WomenDepartment class, but we will also need to alter checkIn() method. This will apparently violate the single responsibility principle (SRP). This is because a class should have only one reason to change. Here the checkIn() method depends heavily on data structure that the two departments use. It has at least two reasons to change.
What if we can hide the underlying data structure that a department uses to store product and provide a universal way to iterator products? This is when we will need the Iterator Pattern.
Let us rework our code base.
First, we will need to create an interface called Iterator:
The Iterator interface defines two methods that the StoreManager will use to iterate the products.
Let us create a concrete iterator for MenDepartment class:
We need an internal pointer in MenDepartment to keep track of the current index.
Let us create a concrete iterator for WomenDepartment class:
Now we need to create a new method (createIterator) for MenDepartment and WomenDepartment. What this method does is to instantiate a concrete iterator designed previously. So that we can get their iterator directly:
Lastly, let us see how StoreManager has changed. Rest all remain the same, the only place we need to change is checkIn() method, and we also need to add a facilitate method checkInByIterator() to make the code cleaner:
As we can see now, StoreManager is anti-fragile. It does not concern the data structures a department uses to store products. The code is now easier to maintain.
In our example, the Iterator Pattern provides a way to access the elements (products) of an aggregate object (MenDepartment and WomenDepartment objects) sequentially without exposing its underlying representations (Array or SqlStack).
Hopefully this simple tutorial helped you with your development.
If you like our post, please follow us on Twitter and help spread the word. We need your support to continue.
If you have questions or find our mistakes in above tutorial, do leave a comment below to let us know.