Composite (padrão de desenho): Difference between revisions

From Wiki**3

No edit summary
Line 1: Line 1:
{{TOCright}}
{{TOCright}}
<!-- Material correspondente à aula 22. ­-->
 
O padrão ''composite'' organiza os objectos em árvores que representam hierarquias parte-todo. O uso do padrão permite que sejam tratados uniformemente os objectos e as suas composições.
O padrão ''composite'' organiza os objectos em árvores que representam hierarquias parte-todo. O uso do padrão permite que sejam tratados uniformemente os objectos e as suas composições.


Line 14: Line 14:


===A Empregada Básica===
===A Empregada Básica===
Uma implementação simples definiria na implementação do conceito ''empregada'' as referências para os objectos que representam as ementas.
Uma implementação simples definiria na implementação do conceito ''empregada'' as referências para os objectos que representam as ementas.


  <B>public</B> <B>class</B> Empregada0 {
  <B>public</B> <B>class</B> Empregada0 {
Line 46: Line 46:


===Refeições a todas as horas===
===Refeições a todas as horas===
Uma possível solução é definir as empregadas como tendo, não dois, três, ou um número concreto de ementas, mas sim como tendo a capacidade de gerir um número indeterminado (uma colecção) de ementas.
Uma possível solução é definir as empregadas como tendo, não dois, três, ou um número concreto de ementas, mas sim como tendo a capacidade de gerir um número indeterminado (uma colecção) de ementas.


   <B>import</B><FONT COLOR="#808000"> java.util.ArrayList;</FONT>
   <B>import</B><FONT COLOR="#808000"> java.util.ArrayList;</FONT>
Line 72: Line 72:


===Sobremesas ao Jantar===
===Sobremesas ao Jantar===
Mas o que aconteceria se se quisesse adicionar uma outra ementa apenas a uma das refeições? Por exemplo, adicionar uma ementa de sobremesas ou uma carta de vinhos à ementa do jantar. A solução anterior não tem limitações ao número de ementas que uma empregada pode gerir. No entanto, adicionar uma ementa à colecção não a associa de forma alguma à ementa do jantar: seria necessário alterar o código da empregada para fazer tal associação: uma situação indesejável. A solução passa por utilizar o padrão de composição (''composite''): por um lado a ementa do jantar vai ter uma outra ementa como se fosse mais uma entrada, por outro a empregada trata a ementa do jantar como sempre fez (i.e., sem alterações).
Mas o que aconteceria se se quisesse adicionar uma outra ementa apenas a uma das refeições? Por exemplo, adicionar uma ementa de sobremesas ou uma carta de vinhos à ementa do jantar. A solução anterior não tem limitações ao número de ementas que uma empregada pode gerir. No entanto, adicionar uma ementa à colecção não a associa de forma alguma à ementa do jantar: seria necessário alterar o código da empregada para fazer tal associação: uma situação indesejável. A solução passa por utilizar o padrão de composição (''composite''): por um lado a ementa do jantar vai ter uma outra ementa como se fosse mais uma entrada, por outro a empregada trata a ementa do jantar como sempre fez (i.e., sem alterações).


   <B>public</B> <B>abstract</B> <B>class</B> ComponenteEmenta {   
   <B>public</B> <B>abstract</B> <B>class</B> ComponenteEmenta {   

Revision as of 02:58, 12 November 2008

O padrão composite organiza os objectos em árvores que representam hierarquias parte-todo. O uso do padrão permite que sejam tratados uniformemente os objectos e as suas composições.

Estrutura

O padrão composite tem a seguinte estrutura de classes:

Composite-dpcd.png

Exemplo

Um restaurante tem empregadas que apresentam menus aos clientes. Cada empregada dispõe de várias ementas, consoante a hora do dia: assim, existem ementas para pequenos almoços, almoços e jantares, por exemplo.

A Empregada Básica

Uma implementação simples definiria na implementação do conceito empregada as referências para os objectos que representam as ementas.

public class Empregada0 {

 Ementa _ementaPequenoAlmoço;
 Ementa _ementaAlmoço;
 Ementa _ementaLanche;

   public Empregada0(Ementa ementaPequenoAlmoço, Ementa ementaAlmoço,
                     Ementa ementaLanche) {
     _ementaPequenoAlmoço = ementaPequenoAlmoço;
     _ementaAlmoço = ementaAlmoço;
     _ementaLanche = ementaLanche;
   }

   public void printMenu() {
     printMenu(ementaAlmoço);
     printMenu(ementaLanche);
   }

   public void printMenu(Ementa ementa) {
     System.out.println(ementa.nome());
       for (ItemEmenta item : ementa)
         System.out.printf("%s, %s%n    -- %s%n", item.nome(),
                           item.preço(), item.descrição());
   }

 }

Esta situação conduz a inflexibilidade na manutenção: por exemplo, a adição de novas refeições implica a alteração das empregadas!

Refeições a todas as horas

Uma possível solução é definir as empregadas como tendo, não dois, três, ou um número concreto de ementas, mas sim como tendo a capacidade de gerir um número indeterminado (uma colecção) de ementas.

 import java.util.ArrayList;

 public class Empregada1 {

   ArrayList<Ementa> _ementas;

   public Empregada1(ArrayList<Ementa> ementas) {
     _ementas = ementas;
   }

   public void printMenu() {
     for (Ementa ementa : _ementas) printMenu(ementa);
   }

   public void printMenu(Ementa ementa) {
     System.out.println(ementa.nome());
     for (ItemEmenta item : ementa)
       System.out.printf("%s, %s%n    -- %s%n", item.nome(),
                         item.preço(), item.descrição());
   }

 }

Sobremesas ao Jantar

Mas o que aconteceria se se quisesse adicionar uma outra ementa apenas a uma das refeições? Por exemplo, adicionar uma ementa de sobremesas ou uma carta de vinhos à ementa do jantar. A solução anterior não tem limitações ao número de ementas que uma empregada pode gerir. No entanto, adicionar uma ementa à colecção não a associa de forma alguma à ementa do jantar: seria necessário alterar o código da empregada para fazer tal associação: uma situação indesejável. A solução passa por utilizar o padrão de composição (composite): por um lado a ementa do jantar vai ter uma outra ementa como se fosse mais uma entrada, por outro a empregada trata a ementa do jantar como sempre fez (i.e., sem alterações).

 public abstract class ComponenteEmenta {  

   public void adicionar(ComponenteEmenta componente) {  
     throw new UnsupportedOperationException();  
   }  

   public ComponenteEmenta obtémFilho(int i) {  
     throw new UnsupportedOperationException();  
   }  

   public String nome() {  
     throw new UnsupportedOperationException();  
   }
  
   public String descrição() {  
     throw new UnsupportedOperationException();  
   }  

   public double preço() {  
     throw new UnsupportedOperationException();  
   }  

   public boolean vegetariano() {  
     throw new UnsupportedOperationException();  
   }  

   public void print() {  
     throw new UnsupportedOperationException();  
   }  
 }
 public class Ementa extends ComponenteEmenta {  
     ArrayList<ComponenteEmenta> _componentes = new ArrayList<ComponenteEmenta>();  
     String _nome;  
     String _descrição;  
   
     public Ementa(String nome, String descrição) {  
         _nome = nome;  
         _descrição = descrição;  
     }  
   
     public void adicionar(ComponenteEmenta componente) {  
         _componentes.add(componente);  
     }  
   
     public ComponenteEmenta obtémFilho(int i) {  
         return _componentes.get(i);  
     }  
   
     public String nome() { return _nome; }  
     public String descrição() { return _descrição; }  
   
     public void print() {  
         System.out.printf("%n%s, %s%n", nome(), descrição());  
         System.out.println("--------------------");  
         for (ComponenteEmenta componente : _componentes)  
             componente.print();  
     }  
 } 
 public class ItemEmenta extends ComponenteEmenta {  

     String _nome;  
     String _descrição;  
     boolean _vegetariano;  
     double _preço;  

     public ItemEmenta(String nome, String descrição, boolean vegetariano, double preço) {  
         _nome = nome;  
         _descrição = descrição;  
         _vegetariano = vegetariano;  
         _preço = preço;  
     }  

     public String nome() { return _nome; }  
     public String descrição() { return _descrição; }  
     public double preço() { return _preço; }  
     public boolean vegetariano() { return _vegetariano; }  

     public void print() {  
         System.out.print(nome());  
         if (vegetariano()) System.out.print(" (v)");  
         System.out.println(", " + preço());  
         System.out.println("    -- " + descrição());  
     }  
 }
 public class Empregada2 {  
   private ComponenteEmenta _ementas;  
   public Empregada2(ComponenteEmenta ementas) { _ementas = ementas; }  
   public void printMenu() { _ementas.print(); }  
 }
 public class Restaurante {  
   public static void main(String[] args) {  
     ComponenteEmenta pequenoAlmoço = new Ementa("PEQUENO ALMOÇO", "Pequeno Almoço");  
     ComponenteEmenta almoço        = new Ementa("ALMOÇO", "Almoço");  
     ComponenteEmenta lanche        = new Ementa("LANCHE", "Lanche");  
     ComponenteEmenta jantar        = new Ementa("JANTAR", "Jantar");  
     ComponenteEmenta sobremesas    = new Ementa("SOBREMESAS", "Hmmmm!");  

     ComponenteEmenta refeições = new Ementa("REFEIÇÕES", "Tudo!");  

     refeições.adicionar(pequenoAlmoço);  
     refeições.adicionar(almoço);  
     refeições.adicionar(lanche);  
     refeições.adicionar(jantar);  

     jantar.adicionar(new ItemEmenta("Esparguete", "Esparguete com deliciosas alcaparras",  
                                     true, 5.49));  
     jantar.adicionar(sobremesas);  

     Empregada2 empregada = new Empregada2(refeições);  
     empregada.printMenu();  
   }  
 }