1. Was ist das Iterator-Muster
Das Iterator-Muster ist ein Verhaltensmuster, das eine einheitliche Methode zum Durchlaufen der Elemente eines Aggregatobjekts bietet, ohne die interne Repräsentation des Aggregatobjekts offenzulegen.
2. Merkmale und Vorteile des Iterator-Musters
Die Merkmale und Vorteile des Iterator-Musters sind wie folgt:
- Es kann die interne Struktur des Sammlungsobjekts verbergen und den Traversierungsalgorithmus vom Sammlungsobjekt entkoppeln.
- Es bietet eine standardisierte Methode zum Durchlaufen verschiedener Arten von Sammlungsobjekten.
- Es vereinfacht den Client-Code, macht ihn klarer und prägnanter.
- Es kann verschiedene Implementierungen von Iteratoren bereitstellen, um sich verschiedenen Durchlaufbedürfnissen anzupassen.
3. Beispiele für praktische Anwendungen des Iterator-Musters
Das Iterator-Muster hat viele praktische Anwendungen, wie z.B.:
- Das Durchlaufen eines Datenbank-Abfrageergebnis-Sets.
- Das Durchlaufen von Dateien und Ordnern in einem Dateisystem.
- Das Durchlaufen von Elementen in einer Sammlung.
4. Implementierung des Iterator-Musters in Golang
4.1 UML-Klassendiagramm

4.2 Beispiel-Einführung
Im obigen UML-Klassendiagramm haben wir zwei Hauptrollen: Iterator und Sammlung.
- Der Iterator definiert die Schnittstelle zum Durchlaufen eines Sammlungsobjekts, einschließlich der Methode
HasNext(), um festzustellen, ob ein weiteres Element vorhanden ist, und der MethodeNext(), um das nächste Element zu erhalten. - Der ConcreteIterator ist die spezifische Implementierungsklasse des Iterators, die die Methoden
HasNext()undNext()implementiert. - Die Sammlung definiert die Schnittstelle zum Erstellen von Iteratorobjekten mit der Methode
CreateIterator(). - Die ConcreteCollection ist die spezifische Implementierungsklasse der Sammlung, die die Methode
CreateIterator()implementiert.
4.3 Umsetzungsschritte
Als nächstes werden wir das Iterator-Muster in Golang schrittweise implementieren.
4.3.1 Definition der Iterator-Schnittstelle und der konkreten Iterator-Klasse
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 Definition der Iterable-Objektschnittstelle und der konkreten Iterable-Objektklasse
type Collection interface {
CreateIterator() Iterator
}
type ConcreteCollection struct {
items []interface{}
}
func (c *ConcreteCollection) CreateIterator() Iterator {
return &ConcreteIterator{
collection: c,
index: 0,
}
}
4.3.3 Implementierung der Iterator-Generierunglogik in der Iterable-Objektklasse
func main() {
collection := &ConcreteCollection{
items: []interface{}{"Golang", "Python", "Java"},
}
iterator := collection.CreateIterator()
for iterator.HasNext() {
item := iterator.Next()
fmt.Println(item)
}
}
Das Ausführen des obigen Codes ergibt die folgende Ausgabe:
Golang
Python
Java
In dem obigen Code definieren wir eine ConcreteCollection-Klasse, die die Collection-Schnittstelle implementiert, wobei ihre CreateIterator()-Methode ein Iteratorobjekt zurückgibt. Wir verwenden dieses Iteratorobjekt in der main()-Funktion zur Traversierung.
4.4 Implementierungsschrittserweiterung: Vereinfachte Implementierung des Iterators mithilfe von Generatorfunktionen
In Golang können wir die Implementierung von Iteratoren mithilfe einer Generatorfunktion (yield) vereinfachen. Hier ist ein Beispiel zur Verwendung einer Generatorfunktion:
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)
}
}
Im obigen Code definieren wir eine GenerateItems() Funktion, die ein schreibgeschütztes Channel (<-chan) zurückgibt und yield verwendet, um Elemente sequenziell an den Channel innerhalb dieser Funktion zu senden. In der main() Funktion verwenden wir range, um diesen schreibgeschützten Channel zu durchlaufen und die Elementwerte auszugeben.
Auf diese Weise haben wir die Implementierung des Iterators mithilfe einer Generatorfunktion vereinfacht.