segunda-feira, 30 de setembro de 2013

Padrão de Projeto Iterator

Padrão Iterator

        Imagine que você trabalha em uma rede de supermercado e tenha que mostrar uma lista de produtos, Refrigerante e Bolachas recheadas. Ai você descobre que a lista de refrigerantes foi criada utilizando Arraylist e os bolachas com Matriz.

Como mostrar ambos produtos? Apesar de ambos serem produtos cada um tem uma forma diferente de implementação.

Você não quer ou não pode padronizar a lista de produtos. Como conseguir mostrar uma lista que contenha ambos produtos?

Bom, poderia fazer um for para cada um e mostrar o produto pelo loop. Assim:

ArrayList<Produto> arrayListDeProdutos = new ArrayList<Produto>();
for (Produto produto : arrayListDeProdutos ) {
 System.out.println(produto.nome);
}

Produto[] matrizDeProdutos = new Produto[3];
for (int i = 0; i < matrizDeProdutos .length; i++) {
 System.out.println(matrizDeProdutos [i].nome);
}


É fácil perceber o problema dessa implantação sem ver o código, caso outra equipe armazene algum produto com outro tipo de estrutura, seria necessário mais um for.
E se precisar fazer alguma operação com a lista de produtos, terá de haver o mesmo método repetido para cada lista com estrutura diferente.

Ok, então vamos ver agora uma boa solução para esse problema.

Vamos conhecer o Padrão Iterator:

Conceito:
O Fornecer uma maneira de acessar sequencialmente os elementos
de um objeto agregado(coleção ou grupo de objetos) sem expor sua implementação.

A interface tem o método hasNext() que determina se há mais elementos no grupo para serem submetidos a iteração.

O método next() retorna o próximo objeto do grupo.

Obs: Quando falamos em coleção estamos nos referindo simplesmente a um grupo de objetos, mesmo que estejam armazenados em estruturas de dados muito diferentes como lista, matrizes hastable eles continuam formando uma coleção de objetos.

As vezes essas coleções são chamadas de Agregados.

A ideia do padrão Iterator é fornecer um meio eficiente de se percorrer todos os elementos de uma determinada coleção e de formas variadas.

O padrão propõe que se utilize uma interface para controlar a iteração. O objeto que implementar esta interface conhece a seqüência do grupo e mantém uma referencia ao elemento atual de forma que possa ser utilizado de forma semelhante à iteração em um array.

O foco principal é em separar a responsabilidade de gerenciar o armazenamento dos dados da coleção, da forma como eles são percorridos.
  •   Um iterador simples poderia percorrer a lista em ordem sequencial.
  •   Um outro iterador poderia filtrar alguns dados para serem percorridos.
  •   Um outro ainda, poderia percorrer a sequência segundo algum critério de ordenação.

ESTRUTURA BASICA:



Então, respondendo ao exemplo anterior, ao utilizar o padrão iterator nós podemos acessar os elementos de um conjunto de dados sem conhecer como se deu sua implementação, não há a necessidade de se preocupar se ele foi estruturado com Arraylist ou Matriz.

O método da criação do iterator retorna um iterador de Lista que tem o ArrayList produtos como conjunto. Para a classe que utiliza matriz para armazenar os produtos esse método cria um Iterator que retorna um iterador de Matriz

Pronto, agora os diferentes conjuntos estão encapsulados numa interface comum. Agora falta implementar os iteradores.

A lista será mostrada pela Interface comum aos produtos criada para o Iterator.

A Interface do Iterador define um TIPO para acessar os elementos de uma coleção qualquer.
Ele está implementado com os métodos genéricos para percorre uma coleção:

  • boolean hasNext() : Determina se há um próximo elemento apontado pelo iterador
  • Object next(): Recupera o próximo elemento apontado pelo iterador  
  • void remove(): Remove o elemento recuperado pelo iterador

Como criar um Iterador?

Simples, importar ele e definir a coleção a ser iterada:
import java.util.ArrayList;
import java.util.Iterator;


Exemplo de Iteração:
import java.util.ArrayList;
import java.util.Iterator;
public class produtos {
 public static void main(String args[]) {
  ArrayList<String> produtos = new ArrayList<String>();
   //Adicionando elementos no array
   produtos.add("Coca-Cola");
   produtos.add("Pepsi");
   produtos.add("Sprite");
   produtos.add("Guarana");
   produtos.add("Sukita");
   produtos.add("Kuat");
   produtos.add("Fruki");
  
  //Criacao do Iterador
  Iterator<String> it = produtos.iterator();
  System.out.println("Tamanho da Lista antes da Iteração " + produtos.size());

  //Usando o Iterator pra checar se tem produtos
  while (it.hasNext()) {
   //Obtemos o proximo elemento
   String s = it.next();
   System.out.println(s);
   //Se nao for Coca-Cola, remove
   if (!s.equals("Coca-Cola")) {
    it.remove();
   }
  }
  System.out.println("\nTamanho da Lista depois da Iteração " +
  produtos.size());
  for(String s: produtos){
   System.out.println(s);
  }
 }
}


SAIDA DESSE EXEMPLO:
Tamanho da Lista antes da Iteração: 7
Coca-Cola
Pepsi
Sprite
Guarana
Sukita
Kuat
Fruki


Tamanho da Lista depois da Iteração: 1
Coca-Cola


Pode se ver neste exemplo uma característica interessante do Iterator, remover ao mesmo tempo que ocorre a iteração.

Vemos então que o Iterator tem uma grande aplicabilidade, como;
  •  Acessar conteúdo de uma coleção sem expor sua representação interna
  •  Suportar múltiplas plataformas de iteração
  •  Prover uma interface única para varrer coleções diferentes, isto é chamado de iteração polimórfica.
Referências:
Use a Cabeça! Padrões de Projeto de Eric & Elisabeth Freeman.
Google Books - Use a Cabeça ! Padrões de Projetos (design Patterns)

Padrão de Projeto Iterator em Java - Conceitos, Funcionamento e Aplicação prática, Devmedia:
http://www.devmedia.com.br/padrao-de-projeto-iterator-em-java-conceitos-funcionamento-e-aplicacao-pratica/28748

Sérgio Taborda’s Weblog por Sérgio Taborda, Iterator:
http://sergiotaborda.wordpress.com/desenvolvimento-de-software/java/patterns/iterator/



Marcos Vinicius Scholl:
Graduando em Tecnologia em Análise e Desenvolvimento de Sistemas - TADS 
Universidade Federal do Rio Grande - FURG 
Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Sul IFRS - Campus Rio Grande 
Rua Eng. Alfredo Huch, 475 - Rio Grande, RS - Brasil - 96201-460

Sobre o autor:
Marcos Vinicius Scholl está na internet desde o longínquo ano de 2002. Estuda na área de Tecnologia de Informação. É entusiasta na área de tecnologia. Gremista de paixão e anticolorado por prazer!

5 comentários:

  1. As bolachas, comi antes de fazer a implementação.
    // Interface do iterador tem os metodos next e hasNext()

    public class IteratorMatriz implements iterator {
    public Produto[] lista;
    public int contador;

    public IteratorMatrizDeProdutos(Produto[] lista) {
    this.lista = lista;
    }
    // start da lista
    int contador= 0;

    public void next() {
    contador++;
    }


    public boolean hasNext() {
    return contador == lista.length;
    }
    }

    Então declarar um método de interface que retorne essa matriz.


    Assim temos os dados bem encapsulados.

    for (IteratorInterface it = matrizDeProdutos.iterator(); !it.hasNext(); it.next()) {
            System.out.println( (nome) it.next() );
        }

    Não sei se fui 100% correto, mas o conceito é este.

    ResponderExcluir
  2. Ok, mas esse problema é meio artificial... pois a linguagem já resolvi
    ele. Afinal se na implementação inicial fosse usado o foreach no lugar do for simples já seria um unico tipo de iteração (problema resolvido).

    Claro que o foreach é um for com iterator 'disfarçado'(Syntax Sugar?).

    Pra deixar o artigo mais interessante no lugar do ArrayList e do array[] poderia ser criada uma classe CarrinhoDeCompras. Ainda seria possível percorre-la com foreach? Você poderia fazer um exemplo assim? Acho que isso vai exemplificar bem o uso do iterator e da interface iterable

    ResponderExcluir