Iterator é um padrão de design que faz parte dos padrões comportamentais. O padrão Iterator é utilizado para fornecer uma maneira padronizada de percorrer um grupo de objetos. O padrão Iterator é amplamente utilizado no Java Collection Framework. A interface Iterator fornece métodos para percorrer uma coleção.
Padrão de Design Iterator
De acordo com o GoF, a intenção do padrão de design Iterator é:
Fornecer uma maneira de acessar os elementos de um objeto agregado sem expor sua representação subjacente.
O padrão Iterator não se limita apenas a percorrer uma coleção; podemos fornecer diferentes tipos de iteradores com base em nossos requisitos. O padrão Iterator oculta a implementação real da travessia pela coleção, e os programas clientes apenas utilizam os métodos do iterador.
Exemplo do Padrão Iterator
Vamos entender o padrão do iterador com um exemplo simples. Suponha que tenhamos uma lista de canais de rádio e o programa cliente deseja percorrê-los um por um ou com base no tipo de canal. Por exemplo, alguns programas clientes estão interessados apenas em canais em inglês e desejam processar apenas eles, sem querer processar outros tipos de canais. Então podemos fornecer uma coleção de canais ao cliente e permitir que eles escrevam a lógica para percorrê-los e decidir se devem processá-los. Mas essa solução tem muitos problemas, como o cliente ter que criar a lógica para a travessia. Não podemos garantir que a lógica do cliente está correta. Além disso, se o número de clientes aumentar, será muito difícil manter. Aqui podemos usar o padrão do iterador e fornecer iteração com base no tipo de canal. Devemos garantir que o programa cliente possa acessar a lista de canais apenas através do iterador. A primeira parte da implementação é definir o contrato para nossas interfaces de coleção e iterador. `ChannelTypeEnum.java
`
package com.journaldev.design.iterator;
public enum ChannelTypeEnum {
ENGLISH, HINDI, FRENCH, ALL;
}
ChannelTypeEnum é um enum java que define todos os diferentes tipos de canais. `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 é uma classe POJO simples que possui atributos frequência e tipo de canal. `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);
}
A interface ChannelCollection define o contrato para a implementação de nossa classe de coleção. Observe que existem métodos para adicionar e remover um canal, mas não há um método que retorne a lista de canais. ChannelCollection possui um método que retorna o iterador para travessia. A interface ChannelIterator define os seguintes métodos; ChannelIterator.java
package com.journaldev.design.iterator;
public interface ChannelIterator {
public boolean hasNext();
public Channel next();
}
Agora que nossa interface base e classes principais estão prontas, vamos prosseguir com a implementação da classe de coleção e do iterador. 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;
}
}
}
Observe a implementação da classe interna de iterador para que a implementação não possa ser usada por nenhuma outra coleção. A mesma abordagem é seguida pelas classes de coleção e todas elas têm uma implementação de classe interna da interface Iterator. Vamos escrever um programa de teste padrão de iterador simples para usar nossa coleção e iterador para percorrer a coleção de canais. 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("******");
// Iterador de Tipo de Canal
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;
}
}
Ao executar o programa acima, ele produz a seguinte saída;
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
Pontos Importantes do Padrão de Projeto Iterador
- O padrão de projeto Iterador é útil quando você deseja fornecer uma maneira padrão de iterar sobre uma coleção e ocultar a lógica de implementação do programa cliente.
- A lógica para iteração está embutida na própria coleção e ajuda o programa cliente a iterar sobre eles facilmente.
Padrão de Projeto Iterator no JDK
Todos nós sabemos que o Iterator do framework de Coleção é o melhor exemplo de implementação do padrão iterator, mas você sabia que a classe java.util.Scanner
também implementa a interface Iterator? Leia este post para aprender sobre Classe Scanner do Java. Isso é tudo para o padrão de projeto iterator, espero que seja útil e fácil de entender.
Source:
https://www.digitalocean.com/community/tutorials/iterator-design-pattern-java