O Iterator é um padrão comportamental que permite percorrer elementos de uma coleção sem expor sua representação subjacente (lista, pilha, árvore, etc.). O padrão fornece uma maneira de acessar sequencialmente os elementos de um objeto agregado sem expor sua estrutura interna.
- Quando você precisa acessar o conteúdo de uma coleção sem expor sua estrutura interna
- Quando você quer suportar múltiplos tipos de travessia para uma coleção
- Quando você quer fornecer uma interface uniforme para percorrer diferentes estruturas de dados
- Quando você precisa separar a lógica de travessia da lógica de negócios
from abc import ABC, abstractmethod
from typing import Any, List, Optional
# Interface do Iterator
class Iterator(ABC):
@abstractmethod
def has_next(self) -> bool:
pass
@abstractmethod
def next(self) -> Any:
pass
@abstractmethod
def current(self) -> Any:
pass
@abstractmethod
def reset(self) -> None:
pass
# Interface da Coleção
class IterableCollection(ABC):
@abstractmethod
def create_iterator(self) -> Iterator:
pass
# Iterator Concreto
class PlaylistIterator(Iterator):
def __init__(self, playlist: 'Playlist'):
self._playlist = playlist
self._index = 0
def has_next(self) -> bool:
return self._index < len(self._playlist.songs)
def next(self) -> Any:
if self.has_next():
song = self._playlist.songs[self._index]
self._index += 1
return song
return None
def current(self) -> Any:
if 0 <= self._index < len(self._playlist.songs):
return self._playlist.songs[self._index]
return None
def reset(self) -> None:
self._index = 0
# Coleção Concreta
class Playlist(IterableCollection):
def __init__(self, name: str):
self.name = name
self.songs: List[Song] = []
def add_song(self, song: 'Song') -> None:
self.songs.append(song)
def remove_song(self, song: 'Song') -> None:
self.songs.remove(song)
def create_iterator(self) -> Iterator:
return PlaylistIterator(self)
# Classe que representa uma música
class Song:
def __init__(self, title: str, artist: str, duration: int):
self.title = title
self.artist = artist
self.duration = duration # em segundos
def __str__(self) -> str:
minutes = self.duration // 60
seconds = self.duration % 60
return f"{self.title} - {self.artist} ({minutes}:{seconds:02d})"
# Iterator Reverso (exemplo de iterator alternativo)
class ReversePlaylistIterator(Iterator):
def __init__(self, playlist: Playlist):
self._playlist = playlist
self._index = len(playlist.songs) - 1
def has_next(self) -> bool:
return self._index >= 0
def next(self) -> Any:
if self.has_next():
song = self._playlist.songs[self._index]
self._index -= 1
return song
return None
def current(self) -> Any:
if 0 <= self._index < len(self._playlist.songs):
return self._playlist.songs[self._index]
return None
def reset(self) -> None:
self._index = len(self._playlist.songs) - 1
def main():
# Criando uma playlist
rock_playlist = Playlist("Rock Classics")
# Adicionando músicas
rock_playlist.add_song(Song("Stairway to Heaven", "Led Zeppelin", 482))
rock_playlist.add_song(Song("Bohemian Rhapsody", "Queen", 354))
rock_playlist.add_song(Song("Sweet Child O' Mine", "Guns N' Roses", 356))
# Usando o iterator normal
print("Reproduzindo playlist em ordem normal:")
iterator = rock_playlist.create_iterator()
while iterator.has_next():
print(iterator.next())
# Usando o iterator reverso
print("\nReproduzindo playlist em ordem reversa:")
reverse_iterator = ReversePlaylistIterator(rock_playlist)
while reverse_iterator.has_next():
print(reverse_iterator.next())
if __name__ == "__main__":
main()- Princípio da Responsabilidade Única: separa a lógica de travessia da coleção
- Princípio Aberto/Fechado: pode implementar novos tipos de coleções e iterators sem quebrar o código existente
- Permite percorrer a mesma coleção em paralelo usando diferentes iterators
- Simplifica a interface da coleção
- Permite diferentes tipos de travessia para a mesma coleção
- Pode ser um exagero para estruturas de dados simples
- Usar um iterator pode ser menos eficiente que percorrer elementos diretamente
- Adiciona complexidade ao código quando a lógica de iteração é simples
- Considere implementar métodos adicionais como
previous(),first(),last() - Implemente proteção contra modificações concorrentes da coleção durante a iteração
- Decida se o iterator deve ter acesso direto aos elementos da coleção
- Considere implementar iterators especializados para diferentes casos de uso
- Avalie se precisa de suporte para iteração bidirecional