1. Qu'est-ce que le modèle de l'itérateur
Le modèle de l'itérateur est un modèle de conception comportemental qui fournit une méthode uniforme pour traverser les éléments d'un objet agrégé sans exposer la représentation interne de cet objet agrégé.
2. Caractéristiques et avantages du modèle de l'itérateur
Les caractéristiques et avantages du modèle de l'itérateur sont les suivants:
- Il peut masquer la structure interne de l'objet collection, en dissociant l'algorithme de parcours de l'objet collection.
- Il fournit une manière standardisée de traverser différents types d'objets collection.
- Il simplifie le code client, le rendant plus clair et plus concis.
- Il peut fournir différentes implémentations d'itérateurs pour s'adapter à divers besoins de parcours.
3. Exemples d'applications pratiques du modèle de l'itérateur
Le modèle de l'itérateur a de nombreuses applications pratiques, telles que:
- Le parcours d'un ensemble de résultats de requête de base de données.
- Le parcours de fichiers et de dossiers dans un système de fichiers.
- Le parcours des éléments dans une collection.
4. Implémentation du modèle de l'itérateur en Golang
4.1 Diagramme de classe UML
4.2 Introduction à l'exemple
Dans le diagramme de classe UML ci-dessus, nous avons deux rôles principaux : Itérateur et Collection.
- L'itérateur définit l'interface pour traverser un objet collection, y compris la méthode
HasNext()
pour déterminer s'il y a un autre élément et la méthodeNext()
pour obtenir l'élément suivant. - Le ConcreteIterator est la classe d'implémentation spécifique de l'itérateur, qui implémente les méthodes
HasNext()
etNext()
. - La Collection définit l'interface pour la création d'objets itérateurs, avec la méthode
CreateIterator()
. - Le ConcreteCollection est la classe d'implémentation spécifique de la Collection, qui implémente la méthode
CreateIterator()
.
4.3 Étapes de mise en œuvre
Ensuite, nous mettrons en œuvre le modèle de l'itérateur en Golang étape par étape.
4.3.1 Définir l'interface de l'itérateur et la classe d'itérateur concrète
type Iterator interface {
HasNext() bool
Next() interface{}
}
type ConcreteIterator struct {
collection *ConcreteCollection
index int
}
func (it *ConcreteIterator) HasNext() bool {
if it.index < len(it.collection.items) {
return true
}
return false
}
func (it *ConcreteIterator) Next() interface{} {
if it.HasNext() {
item := it.collection.items[it.index]
it.index++
return item
}
return nil
}
4.3.2 Définir l'interface d'objet itérable et la classe d'objet itérable concrète
type Collection interface {
CreateIterator() Iterator
}
type ConcreteCollection struct {
items []interface{}
}
func (c *ConcreteCollection) CreateIterator() Iterator {
return &ConcreteIterator{
collection: c,
index: 0,
}
}
4.3.3 Implémenter la logique de génération de l'itérateur dans la classe d'objet itérable
func main() {
collection := &ConcreteCollection{
items: []interface{}{"Golang", "Python", "Java"},
}
iterator := collection.CreateIterator()
for iterator.HasNext() {
item := iterator.Next()
fmt.Println(item)
}
}
En exécutant le code ci-dessus, nous obtiendrons la sortie suivante:
Golang
Python
Java
Dans le code ci-dessus, nous définissons une classe ConcreteCollection
qui implémente l'interface Collection
, avec sa méthode CreateIterator()
renvoyant un objet itérateur. Nous utilisons cet objet itérateur dans la fonction main()
pour le parcours.
4.4 Extension de l'étape de mise en œuvre : Simplification de l'implémentation de l'itérateur à l'aide d'une fonction génératrice
En Golang, nous pouvons simplifier l'implémentation des itérateurs en utilisant une fonction génératrice (yield
). Voici un exemple d'utilisation d'une fonction génératrice :
func GenerateItems() <-chan interface{} {
items := []interface{}{"Golang", "Python", "Java"}
out := make(chan interface{})
go func() {
defer close(out)
for _, item := range items {
out <- item
}
}()
return out
}
func main() {
for item := range GenerateItems() {
fmt.Println(item)
}
}
Dans le code ci-dessus, nous définissons une fonction GenerateItems()
qui renvoie un canal en lecture seule (<-chan
), et utilisons yield
pour envoyer séquentiellement les éléments vers le canal à l'intérieur de cette fonction. Dans la fonction main()
, nous utilisons range
pour parcourir ce canal en lecture seule et afficher les valeurs des éléments.
Ainsi, nous avons simplifié l'implémentation de l'itérateur en utilisant une fonction génératrice.