• Nenhum resultado encontrado

O padr˜ao de projetos Iterator, de acordo com sua defini¸c˜ao, possui o objetivo de: “Prover uma maneira de acessar os elementos de um objeto agregado sequencialmente sem expor sua representa¸c˜ao interna” [Gamma et al., 1994]. Este padr˜ao visa uma melhor forma de intera¸c˜ao com um conjunto de objetos, geralmente dispostos em um arranjo, sem que o usu´ario precise saber de que forma esses objetos s˜ao armazenados. Desta forma, se por acaso v´arios arranjos de objetos s˜ao estruturados de forma diferente, o usu´ario tem a impress˜ao de que o acesso a esses objetos ´e semelhante.

A utiliza¸c˜ao do padr˜ao de projetos Iterator ´e recomendada em situa¸c˜oes onde seja necess´ario acessar objetos agregados sem que a estrutura interna dos mesmos fique exposta ao usu´ario. De uma forma geral, este padr˜ao ´e utilizado para suportar m´ultiplas formas na qual seja poss´ıvel percorrer objetos agregados. Uma das situa¸c˜oes em que isto pode ser utilizado ´e quando, por exemplo, tem-se diferentes estruturas de objetos agregados e necessita-se de uma interface uniforme para percorrer essas diferentes estruturas. Assim, para o usu´ario, n˜ao haver´a diferen¸cas entre as estruturas de objetos agregados.

5.5.1

Exemplo utilizado para este padr˜ao

Para ilustrar a utiliza¸c˜ao do padr˜ao de projetos Iterator, ´e utilizado um exemplo retirado de [Freeman et al., 2004], em que existe o seguinte cen´ario: Duas lojas de comida pretendem fusionar-se, criando apenas uma loja com o card´apio de ambas. Uma loja vende apenas refei¸c˜oes do caf´e da manh˜a e chama-se Pancake House e a outra est´a focada em vender refei¸c˜oes para o almo¸co e jantar, e chama-se Diner House. Cada uma das duas lojas de comida possui seu pr´oprio card´apio.

Ambos os restaurantes possuem um sistema que gerencia os produtos, inclusive seu card´apio. Cada uma utiliza uma classe para armazenar os tipos de pratos pr´oprios. O res- taurante de caf´e da manh˜a possui a classe PancakeHouseMenu e o restaurante de almo¸cos e jantares possui a classe DinerHouseMenu. Por´em a estrutura na qual os dois restaurantes armazenam seus produtos ´e diferente. O restaurante Pancake House armazena seus produ- tos em uma estrutura chamada “ArrayList” (uma lista em Java que pode ser incrementada), e o restaurante Diner House armazena em um “Array” (lista com tamanho definido).

Padrão Iterator 144

Dessa forma, as estruturas que armazenam os card´apios de ambos os restaurantes s˜ao distintas e, por consequˆencia, o acesso aos elementos de cada um dos card´apios tamb´em ´e distinto. Portanto, para que os restaurantes possam se unir, e para que haja facilidade no acesso dos ´ıtens de ambos os card´apios, ´e necess´ario criar uma interface ´unica que possa percorrer ambos os menus sem dificuldade. Para que esta interface de acesso facilitado possa ser utilizada, ´e necess´ario aplicar o padr˜ao Iterator neste cen´ario.

Ao utilizar o padr˜ao Iterator, ´e necess´ario, criar uma classe de intera¸c˜ao para ambos os card´apios. Dessa forma, criaram-se as classes DinerMenuIterator e PancakeHouseMenuI- terator. Ambas as classes implementam a interface Iterator. E esta interface possui apenas dois m´etodos, um para verificar se ainda existe ´ıtem e o outro para acessar o ´ıtem seguinte do card´apio. Cada uma das classes menu implementa uma interface chamada Menu e foi utilizada uma classe chamada Waiter para servir de acesso entre os card´apios e suas clas- ses “Iterator”. A figura 5.10 mostra um diagrama de classes simplificado deste cen´ario. As classes sobrepostas possuem implementa¸c˜ao similar `as classes que as sobrep˜oem.

Cada classe do tipo Iterator trabalha com a estrutura espec´ıfica dos card´apios. Para o usu´ario final, a impress˜ao vai ser a de que os ´ıtens est˜ao armazenados em uma estrutura similar e que s˜ao acessados da mesma forma. O padr˜ao Iterator permite que diferentes estruturas com objetos agregados possam ser acessadas de forma semelhante apesar de, internamente, possu´ırem formas de acesso distintas.

5.5.2

Compara¸c˜ao das implementa¸c˜oes em Java e ooErlang

A classe MenuItem, tamb´em mostrada na figura 5.10, refere-se aos ´ıtens que s˜ao ar- mazenados no card´apio do restaurante Diner House, ou seja, em uma instˆancia da classe DinerMenu. Essa ´e outra diferen¸ca em rela¸c˜ao `a classe PancakeHouseMenu, que armazena os ´ıtens sem instanciar objetos de nenhuma outra classe, pois utiliza uma estrutura cha- mada Arraylist em Java. Em 5.5.1 e 5.5.2 s˜ao mostrados detalhes principais dos c´odigos em Java e ooErlang da classe DinerMenu.

Conforme pode ser observado, a classe DinerMenu armazena seus ´ıtens (tipos de co- mida) em uma arranjo que possui, como caracter´ıstica principal, uma quantidade limitada de elementos. Outro ponto importante a ser observado ´e que todos os elementos presentes

Figura 5.10: Diagrama de classes do exemplo para o padr˜ao Iterator.

na lista de objetos s˜ao instˆancias da classe MenuItem. Em ooErlang a quantidade de ´ıtens presentes na lista tamb´em ´e limitada e ´e controlada (assim como em Java) pelo atributo max itens, representando a quantidade m´axima de ´ıtens no card´apio deste restaurante.

Ao verificar a implementa¸c˜ao da classe PancakeHouseMenu, observa-se que outra es- trutura foi utilizada para armazenar os ´ıtens. ´E uma estrutura de arranjo, mas que n˜ao precisa necessariamente de instˆancias de outra classe para que armazene os objetos do card´apio. Percebe-se, assim, que o arranjo utilizado em PancakeHouseMenu ´e do tipo “Ar- rayList”. Assim este arranjo n˜ao tem inicialmente uma quantidade limitada de elementos a ser inserida. Os c´odigos mostrados em 5.5.3 e 5.5.4 apresentam os principais detalhes da implementa¸c˜ao da classe PancakeHouseMenu em Java e ooErlang.

Padrão Iterator 146

1 public class DinerMenu implements Menu { 2 static final int MAX_ITEMS = 6; 3 int numberOfItems = 0;

4 MenuItem[] menuItems; 5

6 public DinerMenu() {

7 menuItems = new MenuItem[MAX_ITEMS]; 8

9 addItem("Vegetarian BLT",

10 "(Fakin’) Bacon with lettuce & tomato on whole wheat", 11 true, 2.99);

12 addItem("BLT",

13 "Bacon with lettuce & tomato on whole wheat", 14 false, 2.99);

15 //outros itens... 16 }

17

18 public Iterator createIterator() {

19 return new DinerMenuIterator(menuItems); 20 }

21 }

C´odigo 5.5.1: Classe DinerMenu em Java

Verifica-se que, diferentemente das implementa¸c˜oes em Java das classes DinerMenu e PancakeHouseMenu, as implementa¸c˜oes em ooErlang utilizam ambas a mesma estrutura de armazenamento dos ´ıtens do card´apio. E essa estrutura ´e uma lista simples, que ´e largamente utilizada em fun¸c˜oes do Erlang. Mas os dois card´apios n˜ao s˜ao semelhantes em ooErlang por dois motivos: O primeiro ´e que as listas possuem limites distintos de tamanho e o segundo ´e que uma lista armazena instˆancias de outra classe MenuItem e a outra lista insere os elementos diretamente na lista sem instanciar outra classe.

Um ponto importante a ser observado nas implementa¸c˜oes das classes DinerMenu e PancakeHouseMenu ´e a utiliza¸c˜ao do m´etodo createIterator(). Neste m´etodo ´e realizada a instˆancia do objeto que ir´a interagir com todos os ´ıtens dos referidos card´apios. Estes objetos levam em considera¸c˜ao a estrutura na qual os ´ıtens do card´apio est˜ao armazenadas, possibilitando acessar sequencialmente os referidos ´ıtens. Os c´odigos mostrados em 5.5.5 e 5.5.6 apresentam as implementa¸c˜oes em Java e ooErlang da classe DinerMenuIterator.

A implementa¸c˜ao em Java da classe DinerMenuIterator mostra que, o acesso aos ´ıtens ´

e feito diretamente por meio da indexa¸c˜ao da posi¸c˜ao de cada ´ıtem. Sempre que se deseja verificar se existe um novo ´ıtem, deve-se avaliar para saber se j´a chegou-se ao n´umero m´aximo de ´ıtens permitido pela classe DinerMenu. Assim consegue-se implementar, em

1 -class(dinerMenu). 2 -implements(menu).

3 -export([new/0, add_item/4, get_menu_items/0, create_iterator/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 MaxItems; 9 NumberOfItems; 10 MenuItems. 11 12 methods. 13 14 new() -> 15 self::MenuItems = [], 16 add_item("Vegetarian BLT",

17 "(Fakin’) Bacon with lettuce & tomato on whole wheat", 18 true, 2.99),

19 add_item("BLT",

20 "Bacon with lettuce & tomato on whole wheat", 21 false, 2.99). 22 %outros itens... 23 24 create_iterator() -> 25 NewIterator = dinerMenuIterator::new(self::MenuItems), 26 NewIterator.

C´odigo 5.5.2: Classe DinerMenu em ooErlang

DinerMenuIterator os dois m´etodos principais para que seja poss´ıvel percorrer os ´ıtens do card´apio do restaurante: next(), para acessar o elemento seguinte ao atual e hasNext() para verificar se ainda existem elementos n˜ao visitados.

Pode ser verificado que, na implementa¸c˜ao da classe DinerMenuIterator, tanto em Java quanto em ooErlang, cada elemento pertencente ao card´apio de uma instˆancia da classe Di- nerMenu ´e um objeto da classe MenuItem. Isto n˜ao ´e o mesmo que ocorre na implementa¸c˜ao da classe PancakeHouseMenu, onde cada elemento do card´apio ´e inserido diretamente em um “ArrayList” na implementa¸c˜ao em Java. Em ooErlang a inser¸c˜ao dos elementos ocorre em uma lista semelhante `a implementada no c´odigo mostrado em 5.5.2, com a diferen¸ca de que n˜ao ´e utilizada a classe MenuItem para instanciar os objetos.

Ambas as classes DinerMenuIterator e PancakeHouseMenuIterator s˜ao utilizadas para percorrer todos os elementos pertencentes `as instˆancias das respectivas classes DinerMenu e PancakeHouseMenu. A interface Iterator ´e a implementada pelas classes respons´aveis pelo acesso dos respectivos elementos. A classe que se utiliza da interface Iterator ´e a

Padrão Iterator 148

1 public class PancakeHouseMenu implements Menu { 2 ArrayList menuItems;

3

4 public PancakeHouseMenu() {

5 menuItems = new ArrayList(); 6

7 addItem("K&B’s Pancake Breakfast",

8 "Pancakes with scrambled eggs, and toast",

9 true,

10 2.99);

11

12 addItem("Regular Pancake Breakfast",

13 "Pancakes with fried eggs, sausage",

14 false,

15 2.99);

16

17 } 18

19 public Iterator createIterator() {

20 return new PancakeHouseMenuIterator(menuItems); 21 }

22 }

C´odigo 5.5.3: Classe PancakeHouseMenu em Java

1 -class(pancakeHouseMenu). 2 -implements(menu).

3 -export([new/0, add_item/4, get_menu_items/0, create_iterator/0, to_string/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 MenuItems. 9 10 methods. 11 12 new() -> 13 self::MenuItems = [],

14 add_item("K & B’s Pancake Breakfast",

15 "Pancakes with scrambled eggs, and toast", 16 true, 2.99),

17 add_item("Regular Pancake Breakfast", 18 "Pancakes with fried eggs, sausage", 19 false, 2.99). 20 %outros itens... 21 22 create_iterator() -> 23 NewIterator = pancakeHouseMenuIterator::new(self::MenuItems), 24 NewIterator.

1 public class DinerMenuIterator implements Iterator { 2 MenuItem[] items;

3 int position = 0; 4

5 public DinerMenuIterator(MenuItem[] items) { 6 this.items = items;

7 }

8

9 public Object next() {

10 MenuItem menuItem = items[position]; 11 position = position + 1;

12 return menuItem; 13 }

14

15 public boolean hasNext() {

16 if (position >= items.length || items[position] == null) { 17 return false; 18 } else { 19 return true; 20 } 21 } 22 }

C´odigo 5.5.5: Classe DinerMenuIterator em Java

classe Waitress, sendo de sua responsabilidade acessar ambos os card´apios utilizando-se da mesma interface. Os c´odigos mostrados em 5.5.7 e 5.5.8 apresentam, respectivamente em Java e ooErlang, os detalhes principais da implementa¸c˜ao da classe Waitress.

A classe Waitress possui dois atributos, pancakeHouseMenu e dinerMenu. Estes atri- butos recebem as instˆancias das classes PancakeHouseMenuIterator e DinerMenuIterator respectivamente. Dessa forma ´e possivel manusear os dois card´apios, e utilizar-se da mesma interface para percorrer os ´ıtens dos mesmos. Al´em de um construtor, a classe Waitress possui tamb´em o m´etodo printMenu(), no qual os atributos da classe s˜ao utilizados para que seja poss´ıvel percorrer e imprimir todos os elementos de ambos os card´apios.

A classe principal deste exemplo chama-se MenuTestDrive. Conforme ´e mostrado nos c´odigos 5.5.9 e 5.5.10 que representam as implementa¸c˜oes em Java e ooErlang, nesta ordem, da classe principal, s˜ao testadas as duas classes que implementam a interface Iterator. Para isto, instanciam-se dois objetos, referentes `as classes PancakeHouseMenu e DinerMenu. Em seguida estes objetos s˜ao passados por parˆametro na instancia¸c˜ao do objeto da classe Waitress, criando assim os respectivos objetos de intera¸c˜ao.

Padrão Iterator 150

1 -class(dinerMenuIterator). 2 -implements(iterator).

3 -export([new/1, next/0, has_next/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Items; 9 Position. 10 11 methods. 12 13 new(Items) -> 14 self::Items = Items. 15 16 next() ->

17 MenuItem = lists:nth(self::Position, self::Items), 18 self::Position = self::Position + 1, 19 MenuItem. 20 21 has_next() -> 22 Pos = self::Position, 23 Itm = self::Items, 24 if 25 (Pos >= length(Itm)) -> 26 false; 27 true -> 28 true 29 end.

C´odigo 5.5.6: Classe DinerMenuIterator em ooErlang

um objeto da classe Waitress, os parˆametros recebidos na instancia¸c˜ao s˜ao instˆancias das classes que possuem os diferentes card´apios de produtos. Quando a instˆancia da classe Waitress invoca o m´etodo printMenu(), na classe Waitress, internamente, s˜ao criadas as instˆancias das classes que implementam a interface Iterator e que s˜ao respons´aveis por percorrer ambas as listas de produtos. Assim, com a chamada de apenas um m´etodo foi poss´ıvel verificar os elementos de duas diferentes agrega¸c˜oes.

As figuras mostradas em 5.11 e 5.12 mostram a execu¸c˜ao do exemplo que implementa o padr˜ao de projetos Iterator em Java e ooErlang, respectivamente. Verifica-se que, ambas as implementa¸c˜oes utilizaram os mesmos ´ıtens de card´apio, para que a compara¸c˜ao das execu¸c˜oes possa demonstrar semelhan¸ca nas implementa¸c˜oes realizadas em Java e ooEr- lang. S˜ao percorridas as listas de produtos dos card´apios das classe PancakeHouseMenu e DinerMenu, nesta sequˆencia, imprimindo cada ´ıtem de cada card´apio.

1 public class Waitress {

2 PancakeHouseMenu pancakeHouseMenu; 3 DinerMenu dinerMenu;

4

5 public Waitress(PancakeHouseMenu pancakeHouseMenu, DinerMenu dinerMenu) { 6 this.pancakeHouseMenu = pancakeHouseMenu;

7 this.dinerMenu = dinerMenu;

8 }

9

10 public void printMenu() {

11 Iterator pancakeIterator = pancakeHouseMenu.createIterator(); 12 Iterator dinerIterator = dinerMenu.createIterator();

13 14 System.out.println("MENU\n----\nBREAKFAST"); 15 printMenu(pancakeIterator); 16 System.out.println("\nLUNCH"); 17 printMenu(dinerIterator); 18 } 19

20 private void printMenu(Iterator iterator) { 21 while (iterator.hasNext()) {

22 MenuItem menuItem = (MenuItem)iterator.next(); 23 System.out.print(menuItem.getName() + ", "); 24 System.out.print(menuItem.getPrice() + " -- "); 25 System.out.println(menuItem.getDescription());

26 }

27 }

C´odigo 5.5.7: Classe Waitress em Java

No exemplo mostrado, o padr˜ao de projetos Iterator ´e utilizado no caso espec´ıfico em que h´a a necessidade de acesso a diferentes conjuntos de objetos (agrega¸c˜oes) utilizando-se de uma mesma interface. Desta forma, para o usu´ario, os acessos realizados nos diferentes conjuntos de objetos aparentam ter sido executados de forma semelhante por terem utili- zado uma interface em comum, entretanto, estes objetos est˜ao armazenados em diferentes estruturas, e seu acesso ´e, logicamente, diferente.

Para que seja poss´ıvel utilizar uma mesma interface com o objetivo de acessar conjuntos de objetos diferentes de forma semelhante, s˜ao modeladas classes que implementam esta interface e, internamente, tratam do acesso espec´ıfico de cada estrutura de armazenamento. O usu´ario, ao se utilizar de um sistema que possui esta modelagem n˜ao ir´a precisar se preocupar com a estrutura interna de cada agrega¸c˜ao de objetos a ser percorrida pelo sistema.

Padrão Iterator 152

1 -class(waitress).

2 -export([new/2, print_menu/0, print_menu/1]).

3 -export([print_vegetarian_menu/0, is_item_vegetarian/1]). 4 -export([print_vegetarian_menu/1, is_vegetarian/2]). 5 -constructor([new/2]). 6 7 attributes. 8 9 PancakeHouseMenu; 10 DinerMenu. 11 12 methods. 13 14 new(PancakeHouseMenu,DinerMenu) -> 15 self::PancakeHouseMenu = PancakeHouseMenu, 16 self::DinerMenu = DinerMenu. 17 18 print_menu() -> 19 Pancake = self::PancakeHouseMenu, 20 Diner = self::DinerMenu, 21 22 PancakeIterator = Pancake::create_iterator(), 23 DinerIterator = Diner::create_iterator(), 24 25 io:format("MENU~n----~nBREAKFAST~n"), 26 print_the_menu(Pancake::MenuItems), 27 io:format("~nLUNCH~n"), 28 print_the_menu(Diner::MenuItems).

C´odigo 5.5.8: Classe Waitress em ooErlang

1 public class MenuTestDrive {

2 public static void main(String args[]) {

3 PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); 4 DinerMenu dinerMenu = new DinerMenu();

5

6 Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu); 7

8 waitress.printMenu();

9 }

C´odigo 5.5.9: Classe principal MenuTestDrive em Java

lhantes por´em com estruturas diferentes em um ´unico sistema. Neste caso, a utiliza¸c˜ao do padr˜ao Iterator tornou possivel a referida associa¸c˜ao sem que fosse necess´ario modificar as estruturas que armazenam os ´ıtens de card´apio de cada sistema. Obt´em-se, dessa forma, uma solu¸c˜ao que n˜ao produz muitos impactos na modelagem como um todo e que facilita a manuten¸c˜ao e extens˜ao do referido sistema.

1 -class(menuTestDrive). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 PancakeHouseMenu = pancakeHouseMenu::new(), 8 DinerMenu = dinerMenu::new(), 9 10 io:format("PancakeHouseMenu: ~p~n", [PancakeHouseMenu]), 11 io:format("DinerMenu: ~p~n", [DinerMenu]),

12 Waitress = waitress::new(PancakeHouseMenu, DinerMenu), 13

14 Waitress::print_menu().

C´odigo 5.5.10: Classe principal MenuTestDrive em ooErlang

Figura 5.11: Execu¸c˜ao do exemplo para o padr˜ao Iterator em Java.

Ao se utilizar do padr˜ao de projetos Iterator, percebe-se que uma das caracter´ısticas ´e a de que este padr˜ao suporta varia¸c˜oes no percorrimento de uma agrega¸c˜ao, sendo poss´ıvel

Padrão Mediator 154

Figura 5.12: Execu¸c˜ao do exemplo para o padr˜ao Iterator em ooErlang.

modificar a forma com a qual o conjunto de elementos ´e visitado. Este padr˜ao tamb´em simplifica a interface da agrega¸c˜ao. Para o exemplo utilizado, torna-se mais simples in- cluir novos card´apios com diferentes estruturas, caso isto se mostre necess´ario, diminuindo problemas em uma possivel extens˜ao do sistema modelado.