Accueil / Tutoriels / Iterator
Iterator
Publié le 17 Mars 2025Iterator (itérateur en français) est un design pattern comportemental qui permet de parcourir les éléments d’une collection sans exposer sa structure interne. Une interface commune à tous les itérateurs est définie pour parcourir les éléments séquentiellement, sans avoir une connaissance détaillée de la structure d’une collection.
Principe
Exemples d’utilisations
Parcourir une collection d’articles de blog
Pagination des résultats d’une requête API
Points d’attentions
Implémenter un itérateur
Exemple d'utilisation d’Iterator en Go
package data
type User struct {
Name string
Age int
}
package iterator
type Iterator[T any] interface {
Next() (*T, bool)
Prev() (*T, bool)
}
package iterator
import (
"iterator/data"
)
type UserIterator struct {
users []data.User
position int
}
func NewUserIterator(users []data.User) *UserIterator {
return &UserIterator{users: users, position: -1}
}
func (it *UserIterator) Next() (*data.User, bool) {
if it.position < len(it.users)-1 {
it.position++
return &it.users[it.position], true
}
return nil, false
}
func (it *UserIterator) Prev() (*data.User, bool) {
if it.position > 0 {
it.position--
return &it.users[it.position], true
}
return nil, false
}
package iteratorCollection
import "iterator"
type IterableCollection[T any] interface {
CreateIterator() iterator.Iterator[T]
}
package iteratorCollection
import (
"iterator/data"
"iterator"
)
type UserCollection struct {
users []data.User
}
func NewUserCollection(users []data.User) *UserCollection {
return &UserCollection{users: users}
}
func (c *UserCollection) CreateIterator() iterator.Iterator[data.User] {
return iterator.NewUserIterator(c.users)
}
package main
import (
"fmt"
"iterator/data"
"iterator/iteratorCollection"
)
func main() {
// Création d'une collection d'utilisateurs
users := []data.User{
{"Toto", 25},
{"Titi", 30},
{"Tata", 22},
}
// Création de la collection et récupération de l'itérateur
userCollection := iteratorCollection.NewUserCollection(users)
iterator := userCollection.CreateIterator()
// Parcours en avant
fmt.Println("Parcours en avant :")
for {
user, hasNext := iterator.Next()
if !hasNext {
break
}
fmt.Printf("Nom: %s, Âge: %d\n", user.Name, user.Age)
}
// Parcours en arrière
fmt.Println("Parcours en arrière :")
for {
user, hasPrev := iterator.Prev()
if !hasPrev {
break
}
fmt.Printf("Nom: %s, Âge: %d\n", user.Name, user.Age)
}
}
Le même exemple en PHP
namespace Practice\DesignPatterns\iterator;
class User
{
public string $name;
public int $age;
public function __construct($name, $age)
{
$this->name = $name;
$this->age = $age;
}
}
namespace Practice\DesignPatterns\iterator;
use SeekableIterator;
class UserCollection {
private array $users;
public function __construct($users) {
$this->users = $users;
}
// Retourne un itérateur pour parcourir la collection
public function getIterator(): SeekableIterator {
return new UserIterator($this->users);
}
}
namespace Practice\DesignPatterns\iterator;
use OutOfBoundsException;
use SeekableIterator;
class UserIterator implements SeekableIterator
{
private array $users;
private int $position;
public function __construct($users)
{
$this->users = array_values($users);
$this->position = 0;
}
// Retourne l'élément actuel
public function current()
{
return $this->users[$this->position];
}
// Retourne la clé actuelle
public function key()
{
return $this->position;
}
// Avance à l'élément suivant
public function next()
{
$this->position++;
}
// Revient au début de la collection
public function rewind()
{
$this->position = 0;
}
// Vérifie si la position actuelle est valide
public function valid()
{
return isset($this->users[$this->position]);
}
// Déplace l'itérateur à une position spécifique
public function seek($offset)
{
if (!isset($this->users[$offset])) {
throw new OutOfBoundsException("Position invalide: $offset");
}
$this->position = $offset;
}
// Retourne à l'élément précédent
public function prev()
{
if ($this->position > 0) {
$this->position--;
}
}
}
declare(strict_types=1);
use Practice\DesignPatterns\iterator\User;
use Practice\DesignPatterns\iterator\UserCollection;
require "./vendor/autoload.php";
$users = [
new User("Toto", 25),
new User("Titi", 30),
new User("Tata", 22)
];
$userCollection = new UserCollection($users);
$iterator = $userCollection->getIterator();
// Parcours en avant
echo "Parcours en avant :\n";
$iterator->rewind();
while ($iterator->valid()) {
$user = $iterator->current();
echo "Nom: {$user->name}, Âge: {$user->age}\n";
$iterator->next();
}
// Utilisation de seek()
echo "Aller directement au 2ème élément :\n";
try {
$iterator->seek(1);
$user = $iterator->current();
echo "Nom: {$user->name}, Âge: {$user->age}\n";
} catch (OutOfBoundsException $e) {
echo $e->getMessage();
}
// Parcours en arrière sécurisé
echo "Parcours en arrière :\n";
// Commence par la dernière position
$iterator->seek(count($users) - 1);
while ($iterator->valid()) {
$user = $iterator->current();
echo "Nom: {$user->name}, Âge: {$user->age}\n";
// Vérification avant d'appeler prev()
if ($iterator->key() == 0) {
break; // Évite la boucle infinie
}
$iterator->prev();
}