Skip to content

Latest commit

 

History

History
164 lines (126 loc) · 5.1 KB

File metadata and controls

164 lines (126 loc) · 5.1 KB

Iterator

O que é?

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 usar?

  • 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

Exemplo em Python

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()

Vantagens

  1. Princípio da Responsabilidade Única: separa a lógica de travessia da coleção
  2. Princípio Aberto/Fechado: pode implementar novos tipos de coleções e iterators sem quebrar o código existente
  3. Permite percorrer a mesma coleção em paralelo usando diferentes iterators
  4. Simplifica a interface da coleção
  5. Permite diferentes tipos de travessia para a mesma coleção

Desvantagens

  1. Pode ser um exagero para estruturas de dados simples
  2. Usar um iterator pode ser menos eficiente que percorrer elementos diretamente
  3. Adiciona complexidade ao código quando a lógica de iteração é simples

Considerações de Implementação

  • 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