Padrão de design Iterator é um dos padrões comportamentais. O padrão Iterator é usado para fornecer uma maneira padrão 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 GoF, a intenção do padrão de design iterator é:
Fornece uma maneira de acessar os elementos de um objeto agregado sem expor sua representação subjacente.
O padrão Iterator não se trata apenas de percorrer uma coleção, podemos fornecer diferentes tipos de iteradores com base em nossos requisitos. O padrão de design Iterator oculta a implementação real da travessia pela coleção e os programas clientes apenas usam métodos do iterador.
Exemplo do Padrão Iterator
Vamos entender o padrão de iterador com um exemplo simples. Suponha que tenhamos uma lista de canais de rádio e o programa do cliente deseja percorrê-los um por um ou com base no tipo de canal. Por exemplo, alguns programas de clientes estão interessados apenas em canais em inglês e desejam processar apenas esses; eles não querem processar outros tipos de canais. Portanto, podemos fornecer uma coleção de canais ao cliente e permitir que eles escrevam a lógica para percorrer os canais e decidir se devem processá-los. No entanto, 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 esteja correta. Além disso, se o número de clientes aumentar, será muito difícil de manter. Aqui, podemos usar o padrão de Iterador e fornecer iteração com base no tipo de canal. Devemos garantir que o programa do cliente possa acessar a lista de canais apenas por meio 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 em 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 tem os 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);
}
interface ChannelCollection define o contrato para a implementação da nossa classe de coleção. Observe que existem métodos para adicionar e remover um canal, mas não há um método que retorna 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 do iterador para que a implementação não possa ser usada por nenhuma outra coleção. A mesma abordagem é seguida também pelas classes de coleção, e todas elas têm a implementação da classe interna da interface Iterator. Vamos escrever um programa de teste simples para o padrão de iterador usando 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 do 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 Design do Iterador
- O padrão de 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 de iteração está incorporada na própria coleção e ajuda o programa cliente a iterar sobre elas facilmente.
Padrão de Projeto Iterator no JDK
Todos sabemos que o Iterator do framework de Coleções é 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 Java Scanner. 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