Thu 11 October 2018
Iterator Design Pattern
Before I started reading the gang of 4 ["Go4"], I was convinced I would not need an iterator. After all, in python, they are already implemented:
x = ['a', 'b', 'c']
for i in x:
print(i)
In the frame of python lists as aggregate objects, the intent of an iterator is satisfied.
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representations.
Displaying notes
Here I explain, how the iterator became my favourite design pattern.
I have written about representation of lists before, and I don't think this will be my last time. When implementing the drop-downs in foolscap to allow a user to see sections contained in their note, I ran into an issue of complexity where I had blocks of conditionals dictating what should be displayed to a user. I wanted the user to have an indication that a note contains sections, and for them to be able to toggle a drop-down to see each section. Similar to:
(+) | circleci |
| docker |
Where my "circleci"
note would contain sections
and the "docker"
note does not. Then expanding:
<-> | circleci |
└─ | -workflow |
| docker |
This is where I realised the abstraction power of an
iterator, And I could hide the collapsed sections
behind an "if"
conditional in an iterator.
class Menu:
def __init__(self, items):
self.items = items
def visible(self):
"""Yield the next appropriate item for display."""
for item in self.items:
yield item.title
if hasattr(item, 'expand') and item.expand:
for sub_item in item.sub_items:
yield sub_item.title
Supporting further traversal policies in my Menu
class is straightforward, and
drawing becomes absurdly simplified:
def draw(menu):
"""Draw all viewable menu items."""
for item in menu.visible():
draw_item(item)
After this I thought of a more complex aggregate structure that I could traverse, like a tree depth first.
Realising the abstraction strength of the iterator, one finds its definition of intent far more compelling.
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representations.