Iterator-Entwurfsmuster ist eines der Verhaltensmuster. Das Iterator-Muster wird verwendet, um eine standardisierte Möglichkeit bereitzustellen, um durch eine Gruppe von Objekten zu traversieren. Das Iterator-Muster wird weit verbreitet in Java Collection Framework verwendet. Das Iterator-Interface bietet Methoden zum Durchlaufen einer Sammlung.
Iterator-Entwurfsmuster
Gemäß dem GoF ist die Absicht des Iterator-Entwurfsmusters:
Bietet eine Möglichkeit, auf die Elemente eines Aggregatobjekts zuzugreifen, ohne dessen zugrunde liegende Darstellung offenzulegen.
Das Iterator-Muster geht nicht nur darum, durch eine Sammlung zu traversieren, wir können verschiedene Arten von Iteratoren basierend auf unseren Anforderungen bereitstellen. Das Iterator-Entwurfsmuster verbirgt die tatsächliche Implementierung der Traversierung durch die Sammlung, und Clientprogramme verwenden einfach Iteratormethoden.
Beispiel für das Iterator-Muster
Lassen Sie uns das Iterator-Muster anhand eines einfachen Beispiels verstehen. Angenommen, wir haben eine Liste von Radiokanälen, und das Client-Programm möchte durch sie hindurchgehen, entweder nacheinander oder basierend auf dem Kanaltyp. Einige Client-Programme interessieren sich beispielsweise nur für englische Kanäle und möchten nur diese verarbeiten. Sie möchten andere Arten von Kanälen nicht verarbeiten. Daher können wir dem Client eine Sammlung von Kanälen zur Verfügung stellen und ihn die Logik schreiben lassen, um durch die Kanäle zu traversieren und zu entscheiden, ob sie verarbeitet werden sollen. Diese Lösung hat jedoch viele Probleme, wie zum Beispiel, dass der Client die Traversierungslogik erstellen muss. Wir können nicht sicherstellen, dass die Client-Logik korrekt ist. Darüber hinaus wird es sehr schwer zu pflegen, wenn die Anzahl der Clients wächst. Hier können wir das Iterator-Muster verwenden und eine Iteration basierend auf dem Kanaltyp bereitstellen. Wir sollten sicherstellen, dass das Client-Programm auf die Liste der Kanäle nur über den Iterator zugreifen kann. Der erste Teil der Implementierung besteht darin, den Vertrag für unsere Sammlungs- und Iterator-Schnittstellen zu definieren. `ChannelTypeEnum.java`
package com.journaldev.design.iterator;
public enum ChannelTypeEnum {
ENGLISH, HINDI, FRENCH, ALL;
}
ChannelTypeEnum ist ein Java-Enum, das alle verschiedenen Arten von Kanälen definiert. `Channel.java`
package com.journaldev.design.iterator;
public class Channel {
private double frequency;
private ChannelTypeEnum TYPE;
public Channel(double freq, ChannelTypeEnum type){
this.frequency=freq;
this.TYPE=type;
}
public double getFrequency() {
return frequency;
}
public ChannelTypeEnum getTYPE() {
return TYPE;
}
@Override
public String toString(){
return "Frequency="+this.frequency+", Type="+this.TYPE;
}
}
Channel ist eine einfache POJO-Klasse mit den Attributen Frequenz und Kanaltyp. `ChannelCollection.java`
package com.journaldev.design.iterator;
public interface ChannelCollection {
public void addChannel(Channel c);
public void removeChannel(Channel c);
public ChannelIterator iterator(ChannelTypeEnum type);
}
Die ChannelCollection-Schnittstelle definiert den Vertrag für die Implementierung unserer Collection-Klasse. Beachten Sie, dass es Methoden zum Hinzufügen und Entfernen eines Kanals gibt, aber keine Methode, die die Liste der Kanäle zurückgibt. ChannelCollection hat eine Methode, die den Iterator für die Traversierung zurückgibt. Die ChannelIterator-Schnittstelle definiert folgende Methoden; ChannelIterator.java
package com.journaldev.design.iterator;
public interface ChannelIterator {
public boolean hasNext();
public Channel next();
}
Jetzt sind unsere Basisschnittstelle und Kernklassen bereit, lassen Sie uns mit der Implementierung der Collection-Klasse und des Iterators fortfahren. ChannelCollectionImpl.java
package com.journaldev.design.iterator;
import java.util.ArrayList;
import java.util.List;
public class ChannelCollectionImpl implements ChannelCollection {
private List<Channel> channelsList;
public ChannelCollectionImpl() {
channelsList = new ArrayList<>();
}
public void addChannel(Channel c) {
this.channelsList.add(c);
}
public void removeChannel(Channel c) {
this.channelsList.remove(c);
}
@Override
public ChannelIterator iterator(ChannelTypeEnum type) {
return new ChannelIteratorImpl(type, this.channelsList);
}
private class ChannelIteratorImpl implements ChannelIterator {
private ChannelTypeEnum type;
private List<Channel> channels;
private int position;
public ChannelIteratorImpl(ChannelTypeEnum ty,
List<Channel> channelsList) {
this.type = ty;
this.channels = channelsList;
}
@Override
public boolean hasNext() {
while (position < channels.size()) {
Channel c = channels.get(position);
if (c.getTYPE().equals(type) || type.equals(ChannelTypeEnum.ALL)) {
return true;
} else
position++;
}
return false;
}
@Override
public Channel next() {
Channel c = channels.get(position);
position++;
return c;
}
}
}
Beachten Sie die innere Klassen-Implementierung der Iterator-Schnittstelle, damit die Implementierung nicht von einer anderen Collection verwendet werden kann. Der gleiche Ansatz wird auch von den Collection-Klassen verfolgt, und alle von ihnen haben eine innere Klassenimplementierung der Iterator-Schnittstelle. Lassen Sie uns ein einfaches Testprogramm für das Iterator-Muster schreiben, um unsere Collection und unseren Iterator zu verwenden, um durch die Sammlung von Kanälen zu traversieren. IteratorPatternTest.java
package com.journaldev.design.iterator;
public class IteratorPatternTest {
public static void main(String[] args) {
ChannelCollection channels = populateChannels();
ChannelIterator baseIterator = channels.iterator(ChannelTypeEnum.ALL);
while (baseIterator.hasNext()) {
Channel c = baseIterator.next();
System.out.println(c.toString());
}
System.out.println("******");
// Kanaltyp-Iterator
ChannelIterator englishIterator = channels.iterator(ChannelTypeEnum.ENGLISH);
while (englishIterator.hasNext()) {
Channel c = englishIterator.next();
System.out.println(c.toString());
}
}
private static ChannelCollection populateChannels() {
ChannelCollection channels = new ChannelCollectionImpl();
channels.addChannel(new Channel(98.5, ChannelTypeEnum.ENGLISH));
channels.addChannel(new Channel(99.5, ChannelTypeEnum.HINDI));
channels.addChannel(new Channel(100.5, ChannelTypeEnum.FRENCH));
channels.addChannel(new Channel(101.5, ChannelTypeEnum.ENGLISH));
channels.addChannel(new Channel(102.5, ChannelTypeEnum.HINDI));
channels.addChannel(new Channel(103.5, ChannelTypeEnum.FRENCH));
channels.addChannel(new Channel(104.5, ChannelTypeEnum.ENGLISH));
channels.addChannel(new Channel(105.5, ChannelTypeEnum.HINDI));
channels.addChannel(new Channel(106.5, ChannelTypeEnum.FRENCH));
return channels;
}
}
Wenn ich das obige Programm ausführe, erzeugt es folgende Ausgabe;
Frequency=98.5, Type=ENGLISH
Frequency=99.5, Type=HINDI
Frequency=100.5, Type=FRENCH
Frequency=101.5, Type=ENGLISH
Frequency=102.5, Type=HINDI
Frequency=103.5, Type=FRENCH
Frequency=104.5, Type=ENGLISH
Frequency=105.5, Type=HINDI
Frequency=106.5, Type=FRENCH
******
Frequency=98.5, Type=ENGLISH
Frequency=101.5, Type=ENGLISH
Frequency=104.5, Type=ENGLISH
Wichtige Punkte des Iterator-Designmusters
- Das Iterator-Muster ist nützlich, wenn Sie eine standardisierte Möglichkeit bereitstellen möchten, um über eine Sammlung zu iterieren und die Implementierungslogik vor dem Clientprogramm zu verbergen.
- Die Logik für die Iteration ist in der Sammlung selbst eingebettet und sie hilft dem Clientprogramm, leicht darüber zu iterieren.
Iterator-Entwurfsmuster in JDK
Wir alle wissen, dass der Iterator des Collection-Frameworks das beste Beispiel für die Implementierung des Iterator-Musters ist, aber wussten Sie, dass die Klasse java.util.Scanner
auch das Iterator-Interface implementiert? Lesen Sie diesen Beitrag, um mehr über die Java-Scanner-Klasse zu erfahren. Das ist alles zum Iterator-Entwurfsmuster, ich hoffe, es ist hilfreich und einfach zu verstehen.
Source:
https://www.digitalocean.com/community/tutorials/iterator-design-pattern-java