Padrões de Projeto
Template Method
Fábio Gondim
Template Method
Intenção [GoF]
“Definir o esqueleto de um algoritmo em uma
operação, postergando alguns passos para as
subclasses. Template Method permite que
subclasses redefinam certos passos de um
algoritmo sem mudar a estrutura do mesmo.”
Resumo
(Fonte: Jacques Philippe Sauvé)
(http://jacques.dsc.ufcg.edu.br/cursos/map/html/pat/template.htm)
– “Um Template Method define um algoritmo
usando operações abstratas”;
– “Subclasses fazem override das operações para
prover um comportamento concreto”;
– “Este padrão é a base para a construção de
frameworks”;
Aplicabilidade [GoF]
O padrão Template Method pode ser usado:
• “Para implementar as partes invariantes de um
algoritmo uma única vez e deixar para as
subclasses a implementação do comportamento
variável”;
• “Quando um comportamento comum entre
subclasses deveria ser fatorado e concentrado
numa classe comum para evitar a duplicação de
código.”;
Aplicabilidade [GoF]
• É um passo freqüente de “refactoring” de
código:
– Primeiro identifique as diferenças no código
existente;
– Separe as diferenças em novas operações
(métodos);
– Substitua o código que apresentava as
diferenças por um método-template que chama
uma dessas novas operações (métodos).
Aplicabilidade [GoF]
• Para controlar extensões de subclasses:
– Você pode definir um Template Method que
chame operações “gancho” (hook) em pontos
específicos, permitindo extensões somente
nestes pontos;
“Faça com que apenas os métodos-gancho possam
sofrer override, usando adjetivos de visibilidade:
- ‘public final’ para o Template Method;
- ‘protected’ para métodos que podem ou devem
sofrer override;”
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
•
Café com Leite e Chá com Limão são
preparados de maneira muito
semelhantes:
–
Receita de Café com Leite
1. Ferver um pouco de água;
2. Misturar o café na água fervente e coá-lo; 3. Servir o café na xícara;
4. Acrescentar açúcar e leite.
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
•
Café com Leite e Chá com Limão são
preparados de maneira muito
semelhantes:
–
Receita de Chá com limão
1. Ferver um pouco de água;
2. Colocar o chá em infusão na água fervente; 3. Despejar o chá na xícara;
4. Acrescentar limão.
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
// Implementação inicial sem o padrão template
protected class CafeComLeite {
public void prepararReceita() {
ferverAgua();
misturarCafe();
servirNaXicara();
adicionarAcucarEleite();
}
//...
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
protected void ferverAgua() {
System.out.println(“Fervendo a água”);
}
protected void misturarCafe() {
System.out.println(“Derramando café
no filtro”);
}
// ...
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
protected void servirNaXicara() {
System.out.println(“Servindo na xícara”);
}
protected void adicionarAcucarEleite() {
System.out.println(“Adicionando Açúcar e Leite”);
}
}
// final da classe
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
// Implementação inicial sem o padrão template
public class ChaComLimao {
public void prepararReceita() {
ferverAgua();
misturarCha();
servirNaXicara();
adicionarLimao();
}
//...
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
protected void ferverAgua() {
System.out.println(“Fervendo a água”);
}
protected void misturarCha() {
System.out.println(“Adicionando a bolsa
de chá”);
}
// ...
Exemplo
Fonte: Use a Cabeça! Padrões de Projeto de Eric Freeman & Elisabeth Freeman
protected void servirNaXicara() {
System.out.println(“Servindo na xícara”);
}
protected void adicionarLimao() {
System.out.println(“Adicionando Limão”);
}
}
// final da classe
Comparando as classes
CafeComLeite e ChaComLimao
•
Observe que as receitas de chá e café
seguem o mesmo algoritmo:
1. Ferver um pouco de água;
2. Usar a água fervida para extrair e misturar
café ou chá;
3. Despejar a bebida resultante em uma xícara;
4. Acrescentar os condimentos apropriados à
bebida
“O padrão Template Method pode ser usado: ...
- Quando um comportamento comum entre subclasses deveria ser fatorado e concentrado numa classe comum para evitar a duplicação de código.”
...
Comparando as classes Café e Chá
Os métodos
ferverAgua()
e
servirNaXicara()
das duas classes são idênticos:
protected void ferverAgua() {
System.out.println(“Fervendo a água”);
}
protected void servirNaXicara() {
System.out.println(“Servindo na xícara”);
}
// método da classe Café
public voidprepararReceita(){ ferverAgua(); misturarCafe(); servir(); adicionarAcucarEleite(); } // método da classe Chá
public voidprepararReceita(){ ferverAgua(); misturarCha(); servir(); adicionarLimao(); }
Os métodos
prepararReceita()
das classes Café e Limão
não são iguais mas são muito parecidos.
- Misturar e coar o pó de café não é muito diferente de colocar o saquinho de chá em infusão: na verdade são procedimentos análogos.
- Da mesma forma, adicionar açúcar e leite não é muito diferente de adicionar limão: em ambos os casos estaremos adicionando condimentos à bebida.
// método da classe Café
public void prepararReceita() { ferverAgua(); misturarCafe(); servir(); adicionarAcucarEleite(); } // método da classe Chá
public void prepararReceita() { ferverAgua();
misturarCha();
servir();
adicionarLimao();
}
Procurando compatibilizar para otimizar
// método comum
public void prepararReceita() { ferverAgua();
fazerInfusao();
servir();
adicionarCondimentos();
}
public abstract class BebidaCafeinada {
// não sobrecarregue o “template method”; para evitar // isto, declare o método template como “final”;
public final void prepararReceita() {
ferverAgua();
fazerInfusao(); // Inversão de Controle
servirNaXicara();
adicionarCondimentos(); // Inversão de Controle
}
protected abstract void fazerInfusao(); protected abstract void adicionarCondimentos(); protected void ferverAgua() {
System.out.println("Fervendo a água"); }
protected void servirNaXicara() {
System.out.println("Servindo na xícara"); }
}
Template Method e a Inversão de Controle
• Em um template method, a superclasse
chama as operações de uma subclasse e
não o contrário. Isto é uma estrutura de
inversão de controle a que alguns se
referem como “princípio de Hollywood”
("Don't call us, we'll call you“)(Não nos
ligue, nós ligaremos para você).
public class CafeComLeite extends BebidaCafeinada { protected void fazerInfusao() {
System.out.println("Derramando café no filtro"); }
protected void adicionarCondimentos() {
System.out.println("Adicionando Açúcar e Leite"); }
}
public class ChaComLimao extends BebidaCafeinada { protected void fazerInfusao() {
System.out.println("Adicionando a bolsa de chá"); }
protected void adicionarCondimentos() {
System.out.println("Adicionando Limão"); }
public class TesteTemplate {
public static void main(String[] args) {
BebidaCafeinada cafe = new CafeComLeite(); BebidaCafeinada cha = new ChaComLimao(); System.out.println("CAFÉ COM LEITE:"); cafe.prepararReceita();
System.out.println("============================"); System.out.println("CHÁ COM LIMÃO:");
cha.prepararReceita(); }
}
CAFÉ COM LEITE:
Fervendo a água
Derramando café no filtro
Servindo na xícara
Adicionando Açúcar e Leite
=========================
CHÁ COM LIMÃO:
Fervendo a água
Adicionando a bolsa de chá
Servindo na xícara
Adicionando Limão
Saída do Programa
Estrutura Genérica
Participantes, Colaborações,
Conseqüências e Considerações
(Fonte: Jacques Philippe Sauvé)
(http://jacques.dsc.ufcg.edu.br/cursos/map/html/pat/template.htm)
Participantes
– ClasseAbstrata
• Define operações abstratas que subclasses
concretas definem para implementar certas etapas do algoritmo;
• Implementa um Template Method definindo o
esqueleto de um algoritmo;
– O Template Method chama várias operações, entre
as quais as operações abstratas da classe.
– ClasseConcreta
• Implementa as operações abstratas para
desempenhar as etapas do algoritmo que tenham comportamento específico a esta subclasse.
Colaborações
– ClasseConcreta depende de ClasseAbstrata
para implementar as partes invariantes do
algoritmo.
Conseqüências
– Template Methods constituem uma das técnicas
básicas de reuso de código;
• São particularmente importantes em frameworks e bibliotecas de classes para o fatoramento de comportamento comum;
– Template Methods levam a uma inversão de
controle conforme explicado anteriormente;
Conseqüências
– O Template Method pode chamar vários tipos de
operações:
• Operações concretas (da ClasseConcreta ou de outras classes)
• Operações concretas de ClasseAbstrata (operações comuns úteis às subclasses)
• Operações abstratas (onde o comportamento varia) – Devem ser sobrescritos (override)
• Factory Methods (assunto que será abordado posteriormente)
• Operações-gancho
– Ver explicação em slide posterior.
Considerações de Implementação
– É importante minimizar o número de operações
abstratas que devem sofrer override para completar
o algoritmo;
• Motivo: simplificação para não chatear o programador
– Convenções de nome:
• Métodos abstratos que devem sofrer override deveriam ter algo de comum no nome
– Exemplo: doXpto() // começa com "do"
• Métodos-gancho que podem sofrer override deveriam ter algo de comum no nome
– Exemplo: logHook() // termina com "Hook"
Operações-gancho (hook operations):
“Fornecem comportamento padrão que subclasses
podem estender se necessário. Uma operação gancho frequentemente não executa nada por padrão.” [GoF]
As operações-gancho, declaradas na superclasse abstrata, não devem ser abstratas, pois as subclasse não devem ser obrigas a implementá-la. Os métodos ganchos só serão sobrescritos pelas subclasses em que forem necessários. Se não houver
comportamento padrão a implementar deverão ser vazios na superclasse.
public void gancho() { }
// Implementado um método-gancho public abstract class BebidaCafeinada {
public final void prepararReceita() {
ferverAgua(); fazerInfusao(); servirNaXicara(); adicionarCondimentos();
gancho(); // Algumas subclasses irão sobrescrever // Quem não sobrescrever não estenderá o comportamento
}
protected abstract void fazerInfusao(); protected abstract void adicionarCondimentos(); protected void ferverAgua() {
System.out.println("Fervendo a água"); }
protected void servirNaXicara() {
System.out.println("Servindo na xícara"); }
protected void gancho() { }
Se você executar a classe TesteTemplate não irá
acontecer nada de diferente porque ninguém
sobrescreveu o método-gancho().
Exercício:
1 - Crie uma classe adicional que sobrescreva o
método-gancho e adicione novo(s)
comportamento(s);
2 – Faça o diagrama de classes do exemplo que
acabamos de implementar.
Exercício
Já temos o café.Que tal um bolo de chocolate para acompanhar o café!
INGREDIENTES:
2 xícaras de farinha de trigo; 2 xícaras de açúcar; 1 xícara de leite;
6 colheres de sopa cheias de chocolate em pó; 1 colher de sopa de fermento em pó; 6 ovos.
Receita do Bolo de
Chocolate com Cobertura
1. Bata as claras em neve, acrescente as gemas e batenovamente, coloque o açúcar (ou adoçante se for um bolo diet) e bata outra vez;
2. Coloque a farinha, o chocolate em pó, o fermento, o leite e bata novamente;
3. Untar um tabuleiro e colocar para assar por aproximadamente 40 minutos em forno médio; 4. Enquanto o bolo assa faça a cobertura com 2 colheres
de chocolate em pó, 1 colher de margarina, meio copo de leite e leve ao fogo até começar a ferver;
5. Jogue a cobertura quente sobre o bolo já assado.
Exercício
Considerando:1. Que cada passo da receita (itens de 1 a 5) seja representado por um método com comandos simples (instruções println’s);
2. Que queremos fazer três bolos de chocolate: um com cobertura e outro sem cobertura (ambos com açúcar) e um terceiro com adoçante e sem cobertura;
Pede-se:
A partir de um design que utilize o padrão Template Method para resolver o problema levantado (faça o diagrama de classes no Jude), escreva o correspondente código em java de todas as classes envolvidas inclusive a classe cliente (teste) que conterá o método main(). Note que no template method, adoçar é um comportamento variável e que fazer e colocar a cobertura são opcionais.
Bibliografia
– GAMMA, E., HELM, R., JOHNSON, R. e VLISSIDES, J.
Padrões de Projeto – Soluções reutilizáveis de software orientado a obetos. Bookman. 1995;
– FREEMAN, Eric, FREEMAN, Elizabeth. Use a Cabeça!
– Padrões de Projeto, Alta Books. 2005;
– LARMAN, Craig. Utilizando UML e Padrões. 2. ed. Bookman. 2002;
– http://jacques.dsc.ufcg.edu.br/cursos/map/html/pat/temp late.htm;