Patron Iterator
Fait partie de la section Programmation orientée objet du Journey Lua de Coddy. Leçon 64 sur 70.
Lorsque tu as une collection d’éléments stockée dans un objet, tu veux souvent les parcourir en boucle. La boucle générique for de Lua fonctionne avec n’importe quelle fonction itératrice : elle appelle la fonction avant chaque passage et s’arrête lorsque la fonction renvoie nil.
Le modèle Iterator donne à l’objet une méthode qui renvoie une telle fonction. La fonction conserve sa position dans une variable locale ; cette position appartient donc à une boucle, et non à la collection :
local Collection = {}
Collection.__index = Collection
function Collection:new()
local obj = { items = {} }
setmetatable(obj, Collection)
return obj
end
function Collection:add(item)
table.insert(self.items, item)
end
function Collection:iter()
local index = 0
return function()
index = index + 1
return self.items[index]
end
endChaque appel à bag:iter() crée une nouvelle fonction avec son propre index, en commençant à 0. La fonction est une fermeture : elle peut encore utiliser index et self après le retour de iter. Après le dernier élément, self.items[index] vaut nil, et la boucle s’arrête :
local bag = Collection:new()
bag:add("apple")
bag:add("banana")
for item in bag:iter() do
print(item) -- apple, puis banana
end
for item in bag:iter() do
print(item) -- apple, puis banana à nouveau
endConserve la position en dehors de la collection elle-même. Si l’objet stockait self.index et servait lui-même d’itérateur, la première boucle laisserait l’index à la fin ; une deuxième boucle n’afficherait donc rien, et une boucle interrompue prématurément avec break ferait commencer la boucle suivante au milieu.
Défi
FacileConstruisons une classe Playlist que tu peux parcourir avec la boucle générique for de Lua ! Tu vas implémenter le modèle Iterator à l’aide d’une méthode :iter() qui renvoie une fonction itératrice.
Tu vas répartir ton code dans deux fichiers :
Playlist.lua: crée une classe Playlist qui stocke les chansons en interne. Ta classe a besoin d’un constructeur:new()qui initialise une liste de chansons vide et d’une méthode:addSong(title)qui y ajoute une chanson. Plus important encore, ajoute une méthode:iter()qui renvoie une nouvelle fonction à chaque appel. Cette fonction conserve sa position dans une variable locale et renvoie la chanson suivante à chaque appel, ounillorsqu’il n’y a plus de chansons.main.lua: charge ton module Playlist et crée une nouvelle liste de lecture. Ajoute-y des chansons à partir des entrées reçues, puis utilise une boucle génériqueforsurplaylist:iter()pour afficher chaque titre de chanson sur sa propre ligne.
Comme chaque appel à :iter() commence à la première chanson, tu peux parcourir la même liste de lecture autant de fois que tu le souhaites.
Tu recevras trois entrées, chacune représentant un titre de chanson à ajouter à ta liste de lecture (dans l’ordre).
Par exemple, si les entrées sont Bohemian Rhapsody, Stairway to Heaven et Hotel California, la sortie devrait être :
Bohemian Rhapsody
Stairway to Heaven
Hotel CaliforniaSi les entrées sont Yesterday, Imagine et Let It Be, la sortie devrait être :
Yesterday
Imagine
Let It BeEssayez vous-même
-- Charger le module Playlist
local Playlist = require('Playlist')
-- Lire trois titres de chansons depuis l’entrée
local song1 = io.read()
local song2 = io.read()
local song3 = io.read()
-- TODO: Créer une nouvelle playlist avec Playlist:new()
-- TODO: Ajouter les trois chansons à la playlist avec :addSong()
-- TODO: Utiliser une boucle for générique sur playlist:iter()
-- et afficher chaque titre de chanson sur sa propre ligne
-- Indice : for song in playlist:iter() do ... end
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Le concept de « self »
Tables avec fonctions« self » expliciteLa syntaxe avec deux-pointsPoint vs deux-pointsRécapitulatif - Point mobile4Projet : Banque numérique
Configuration du projetMéthode de dépôt7Polymorphisme et Redéfinition
Redéfinition de méthodesAppeler des méthodes parentesDuck TypingInterface communeVérification du typeRécapitulatif - Rôles des employés10Projet : Gestionnaire de formes
Configuration du projetClasse RectangleClasse CercleMéthode PérimètreCollection de formesAire totaleFiltrer les formes2Modèle de prototype de classe
Le concept de prototypeLiaison avec __indexLe constructeur :new()Initialisation des attributsInstances indépendantesRécapitulatif - Usine de voitures5Surcharge d'opérateurs en POO
Additionner des objetsSoustraire des objetsConcaténer des objetsComparer des objets (<, >)Récapitulatif - Calculs de portefeuille8Encapsulation
Conventions de nommageClosures pour la confidentialitéAccès via les ClosuresTables en lecture seuleLogique de validationRécapitulatif - Coffre-fort sécurisé11Patrons de conception (Lite)
Fonctions FactoryTable SingletonPatron IteratorObserver (Écouteur)Récapitulatif - Logger Factory3État et comportement des objets
Variables d'instanceMéthodes GetterMéthodes SetterPropriétés calculéesFormatage de chaînesVérifications d'égalitéRécapitulatif - Note de l'étudiant6Bases de l'héritage
Mise en place de l'héritageHériter des méthodesÉtendre le constructeurAjouter des méthodes enfantsPartagé vs UniqueRécapitulatif - Hiérarchie des formesEntraînez-vous par vous-même : Compilateur Lua en ligne