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). | ||
<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é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çã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ç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><ComponenteEmenta> _componentes = <B>new</B> <B><FONT COLOR="#0095ff">ArrayList</FONT></B><ComponenteEmenta>(); | |||
<B><FONT COLOR="#0095ff">String</FONT></B> _nome; | |||
<B><FONT COLOR="#0095ff">String</FONT></B> _descriçã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ção) { | |||
_nome = nome; | |||
_descrição = descriçã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é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ção</FONT>() { <B>return</B> _descriçã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">"</FONT><FONT COLOR="#ff00ff">%n%s</FONT><FONT COLOR="#dd0000">, </FONT><FONT COLOR="#ff00ff">%s%n</FONT><FONT COLOR="#dd0000">"</FONT>, nome(), descrição()); | |||
<B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">"--------------------"</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><ComponenteEmenta> _componentes = <B>new</B> <B><FONT COLOR="#0095ff">ArrayList</FONT></B><ComponenteEmenta>(); | |||
<B><FONT COLOR="#0095ff">String</FONT></B> _nome; | |||
<B><FONT COLOR="#0095ff">String</FONT></B> _descrição; | |||
<FONT COLOR="#800000">boolean</FONT> _vegetariano; | |||
<FONT COLOR="#800000">double</FONT> _preç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ção, <FONT COLOR="#800000">boolean</FONT> vegetariano, <FONT COLOR="#800000">double</FONT> preço) { | |||
_nome = nome; | |||
_descrição = descrição; | |||
_vegetariano = vegetariano; | |||
_preço = preç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é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ção</FONT>() { <B>return</B> _descrição; } | |||
<B>public</B> <FONT COLOR="#800000">double</FONT> <FONT COLOR="#000080">preço</FONT>() { <B>return</B> _preç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">" (v)"</FONT>); | |||
<B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">", "</FONT> + <FONT COLOR="#000080">preço</FONT>()); | |||
<B><FONT COLOR="#0095ff">System</FONT></B>.<FONT COLOR="#000080">out</FONT>.<FONT COLOR="#000080">println</FONT>(<FONT COLOR="#dd0000">" -- "</FONT> + <FONT COLOR="#000080">descriçã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ço = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"PEQUENO ALMOÇO"</FONT>, <FONT COLOR="#dd0000">"Pequeno Almoço"</FONT>); | |||
ComponenteEmenta almoço = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"ALMOÇO"</FONT>, <FONT COLOR="#dd0000">"Almoço"</FONT>); | |||
ComponenteEmenta lanche = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"LANCHE"</FONT>, <FONT COLOR="#dd0000">"Lanche"</FONT>); | |||
ComponenteEmenta jantar = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"JANTAR"</FONT>, <FONT COLOR="#dd0000">"Jantar"</FONT>); | |||
ComponenteEmenta sobremesas = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"SOBREMESAS"</FONT>, <FONT COLOR="#dd0000">"Hmmmm!"</FONT>); | |||
ComponenteEmenta refeições = <B>new</B> <FONT COLOR="#000080">Ementa</FONT>(<FONT COLOR="#dd0000">"REFEIÇÕES"</FONT>, <FONT COLOR="#dd0000">"Tudo!"</FONT>); | |||
refeições.<FONT COLOR="#000080">adicionar</FONT>(pequenoAlmoço); | |||
refeições.<FONT COLOR="#000080">adicionar</FONT>(almoço); | |||
refeições.<FONT COLOR="#000080">adicionar</FONT>(lanche); | |||
refeições.<FONT COLOR="#000080">adicionar</FONT>(jantar); | |||
jantar.<FONT COLOR="#000080">adicionar</FONT>(<B>new</B> <FONT COLOR="#000080">ItemEmenta</FONT>(<FONT COLOR="#dd0000">"Esparguete"</FONT>, <FONT COLOR="#dd0000">"Esparguete com deliciosas alcaparras"</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çõ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:
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();
}
}