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

From Wiki**3

Line 74: Line 74:
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).


  CÓDIGO
  <B>public</B> <B>abstract</B> <B>class</B> ComponenteEmenta { 
    <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">adicionar</FONT>(ComponenteEmenta componente) { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
    <B>public</B> ComponenteEmenta <FONT COLOR="#000080">obt&eacute;mFilho</FONT>(<FONT COLOR="#800000">int</FONT> i) { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
    <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">nome</FONT>() { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    }
 
    <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">descri&ccedil;&atilde;o</FONT>() { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
    <B>public</B> <FONT COLOR="#800000">double</FONT> <FONT COLOR="#000080">pre&ccedil;o</FONT>() { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
    <B>public</B> <FONT COLOR="#800000">boolean</FONT> <FONT COLOR="#000080">vegetariano</FONT>() { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
    <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">print</FONT>() { 
      <B>throw</B> <B>new</B> <B><FONT COLOR="#0095ff">UnsupportedOperationException</FONT></B>(); 
    } 
  }
 
  <B>public</B> <B>class</B> Ementa <B>extends</B> ComponenteEmenta { 
      <B><FONT COLOR="#0095ff">ArrayList</FONT></B>&lt;ComponenteEmenta&gt; _componentes = <B>new</B> <B><FONT COLOR="#0095ff">ArrayList</FONT></B>&lt;ComponenteEmenta&gt;(); 
      <B><FONT COLOR="#0095ff">String</FONT></B> _nome; 
      <B><FONT COLOR="#0095ff">String</FONT></B> _descri&ccedil;&atilde;o; 
   
      <B>public</B> <FONT COLOR="#000080">Ementa</FONT>(<B><FONT COLOR="#0095ff">String</FONT></B> nome, <B><FONT COLOR="#0095ff">String</FONT></B> descri&ccedil;&atilde;o) { 
          _nome = nome; 
          _descri&ccedil;&atilde;o = descri&ccedil;&atilde;o; 
      } 
   
      <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">adicionar</FONT>(ComponenteEmenta componente) { 
          _componentes.<FONT COLOR="#000080">add</FONT>(componente); 
      } 
   
      <B>public</B> ComponenteEmenta <FONT COLOR="#000080">obt&eacute;mFilho</FONT>(<FONT COLOR="#800000">int</FONT> i) { 
          <B>return</B> _componentes.<FONT COLOR="#000080">get</FONT>(i); 
      } 
   
      <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">nome</FONT>() { <B>return</B> _nome; } 
      <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">descri&ccedil;&atilde;o</FONT>() { <B>return</B> _descri&ccedil;&atilde;o; } 
   
      <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">print</FONT>() { 
          <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out.printf</FONT>(<FONT COLOR="#dd0000">&quot;</FONT><FONT COLOR="#ff00ff">%n%s</FONT><FONT COLOR="#dd0000">, </FONT><FONT COLOR="#ff00ff">%s%n</FONT><FONT COLOR="#dd0000">&quot;</FONT>, nome(), descri&ccedil;&atilde;o()); 
          <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">&quot;--------------------&quot;</FONT>); 
          <B>for</B> (ComponenteEmenta componente : _componentes) 
              componente.<FONT COLOR="#000080">print</FONT>(); 
      } 
  }
 
  <B>public</B> <B>class</B> ItemEmenta <B>extends</B> ComponenteEmenta { 
      <B><FONT COLOR="#0095ff">ArrayList</FONT></B>&lt;ComponenteEmenta&gt; _componentes = <B>new</B> <B><FONT COLOR="#0095ff">ArrayList</FONT></B>&lt;ComponenteEmenta&gt;(); 
      <B><FONT COLOR="#0095ff">String</FONT></B> _nome; 
      <B><FONT COLOR="#0095ff">String</FONT></B> _descri&ccedil;&atilde;o; 
      <FONT COLOR="#800000">boolean</FONT> _vegetariano; 
      <FONT COLOR="#800000">double</FONT> _pre&ccedil;o; 
      <B>public</B> <FONT COLOR="#000080">ItemEmenta</FONT>(<B><FONT COLOR="#0095ff">String</FONT></B> nome, <B><FONT COLOR="#0095ff">String</FONT></B> descri&ccedil;&atilde;o, <FONT COLOR="#800000">boolean</FONT> vegetariano, <FONT COLOR="#800000">double</FONT> pre&ccedil;o) { 
          _nome = nome; 
          _descri&ccedil;&atilde;o = descri&ccedil;&atilde;o; 
          _vegetariano = vegetariano; 
          _pre&ccedil;o = pre&ccedil;o; 
      } 
      <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">adicionar</FONT>(ComponenteEmenta componente) { _componentes.<FONT COLOR="#000080">add</FONT>(componente); } 
      <B>public</B> ComponenteEmenta <FONT COLOR="#000080">obt&eacute;mFilho</FONT>(<FONT COLOR="#800000">int</FONT> i) { <B>return</B> _componentes.<FONT COLOR="#000080">get</FONT>(i); } 
      <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">nome</FONT>() { <B>return</B> _nome; } 
      <B>public</B> <B><FONT COLOR="#0095ff">String</FONT></B> <FONT COLOR="#000080">descri&ccedil;&atilde;o</FONT>() { <B>return</B> _descri&ccedil;&atilde;o; } 
      <B>public</B> <FONT COLOR="#800000">double</FONT> <FONT COLOR="#000080">pre&ccedil;o</FONT>() { <B>return</B> _pre&ccedil;o; } 
      <B>public</B> <FONT COLOR="#800000">boolean</FONT> <FONT COLOR="#000080">vegetariano</FONT>() { <B>return</B> _vegetariano; } 
      <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">print</FONT>() { 
          <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">print</FONT>(<FONT COLOR="#000080">nome</FONT>()); 
          <B>if</B> (<FONT COLOR="#000080">vegetariano</FONT>()) <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">print</FONT>(<FONT COLOR="#dd0000">&quot; (v)&quot;</FONT>); 
          <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">&quot;, &quot;</FONT> + <FONT COLOR="#000080">pre&ccedil;o</FONT>()); 
          <B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">&quot;    -- &quot;</FONT> + <FONT COLOR="#000080">descri&ccedil;&atilde;o</FONT>()); 
      } 
  }
 
  <B>public</B> <B>class</B> Empregada2 { 
    <B>private</B> ComponenteEmenta _ementas; 
    <B>public</B> <FONT COLOR="#000080">Empregada2</FONT>(ComponenteEmenta ementas) { _ementas = ementas; } 
    <B>public</B> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">printMenu</FONT>() { _ementas.<FONT COLOR="#000080">print</FONT>(); } 
  }
 
  <B>public</B> <B>class</B> Restaurante { 
    <B>public</B> <FONT COLOR="#800000">static</FONT> <FONT COLOR="#800000">void</FONT> <FONT COLOR="#000080">main</FONT>(<B><FONT COLOR="#0095ff">String</FONT></B>[] args) { 
      ComponenteEmenta pequenoAlmo&ccedil;o = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;PEQUENO ALMO&Ccedil;O&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Pequeno Almo&ccedil;o&quot;</FONT>); 
      ComponenteEmenta almo&ccedil;o        = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;ALMO&Ccedil;O&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Almo&ccedil;o&quot;</FONT>); 
      ComponenteEmenta lanche        = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;LANCHE&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Lanche&quot;</FONT>); 
      ComponenteEmenta jantar        = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;JANTAR&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Jantar&quot;</FONT>); 
      ComponenteEmenta sobremesas    = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;SOBREMESAS&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Hmmmm!&quot;</FONT>); 
      ComponenteEmenta refei&ccedil;&otilde;es = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">&quot;REFEI&Ccedil;&Otilde;ES&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Tudo!&quot;</FONT>); 
      refei&ccedil;&otilde;es.<FONT COLOR="#000080">adicionar</FONT>(pequenoAlmo&ccedil;o); 
      refei&ccedil;&otilde;es.<FONT COLOR="#000080">adicionar</FONT>(almo&ccedil;o); 
      refei&ccedil;&otilde;es.<FONT COLOR="#000080">adicionar</FONT>(lanche); 
      refei&ccedil;&otilde;es.<FONT COLOR="#000080">adicionar</FONT>(jantar); 
      jantar.<FONT COLOR="#000080">adicionar</FONT>(<B>new</B> <FONT COLOR="#000080">ItemEmenta</FONT>(<FONT COLOR="#dd0000">&quot;Esparguete&quot;</FONT>, <FONT COLOR="#dd0000">&quot;Esparguete com deliciosas alcaparras&quot;</FONT>, 
                                      <B>true</B>, <FONT COLOR="#800080">5.49</FONT>)); 
      jantar.<FONT COLOR="#000080">adicionar</FONT>(sobremesas); 
      Empregada2 empregada = <B>new</B> <FONT COLOR="#000080">Empregada2</FONT>(refei&ccedil;&otilde;es); 
      empregada.<FONT COLOR="#000080">mostrarEmentas</FONT>(); 
    } 
  }  


[[category:PO 2005/2006]]
[[category:PO 2005/2006]]

Revision as of 22:55, 15 November 2005

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.

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 {  

     ArrayList<ComponenteEmenta> _componentes = new ArrayList<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 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 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.mostrarEmentas();  
   }  
 }