Este exemplo mostra a aplicação do padrão template method ao "problema" de preparação de uma bebida quente.
Este exemplo mostra a evolução de uma aplicação à medida que são aplicadas técnicas de programação com objectos, em que se refactoriza algum código, e de aplicação de padrões, neste caso, o template method.
Na situação inicial há repetição de código e não há abstracção de conceitos comuns nem, por isso, reutilização.
public class Café {
void preparar() {
ferverÁgua();
juntarGrãosMoídos();
despejarNaChávena();
juntarAçúcar();
}
// &c.
}
public class Chá {
void preparar() {
ferverÁgua();
juntarFolhas();
despejarNaChávena();
juntarLimão();
}
// &c.
}
Nesta situação abstrairam-se algumas das características comuns e procurou-se reutilizar o máximo de funcionalidade. Note-se que, ainda assim, há repetição da estrutura do "algoritmo" de aquecimento.
public abstract class BebidaQuente {
abstract void preparar();
void ferverÁgua() { /* faz coisas */ }
void despejarNaChávena() { /* faz coisas */ }
}
public class Café extends BebidaQuente {
void juntarGrãosMoídos() { /* faz coisas */ }
void juntarAçúcar() { /* faz coisas */ }
void preparar() { /* como antes */ }
}
public class Chá extends BebidaQuente {
void juntarFolhas() { /* faz coisas */ }
void juntarLimão() { /* faz coisas */ }
void preparar() { /* como antes */ }
}
Manteve-se a abstracção conseguida no segundo cenário e aplicou-se o padrão template method. O resultado é o desaparecimento do algoritmo repetido: agora aparece apenas na superclasse e as partes dependentes das subclasses são definidas por cada uma. Note-se que a interface é agora imposta pela superclasse e que pode haver necessidade de renomear alguns dos métodos existentes (ou, alternativamente, de os chamar a partir dos que implementam a interface devida à aplicação do padrão).
public abstract class BebidaQuente {
abstract void infundir();
abstract void condimentar();
void preparar() {
ferverÁgua();
infundir();
despejarNaChávena();
condimentar();
}
void ferverÁgua() { /* faz coisas */ }
void despejarNaChávena() { /* faz coisas */ }
}
class Café extends BebidaQuente {
// void juntarGrãosMoídos() { /* faz coisas */ }
// void juntarAçúcar() { /* faz coisas */ }
public void infundir() { /* juntar grãos moídos */ }
public void condimentar() { /* juntar açúcar */ }
}
class Chá extends BebidaQuente {
// void juntarFolhas() { /* faz coisas */ }
// void juntarLimão() { /* faz coisas */ }
public void infundir() { /* juntar folhas */ }
public void condimentar() { /* juntar limão */ }
}
A chamada pela superclasse de métodos definidos nas subclasses é uma aplicação do chamado "Hollywood Principle", i.e., "don't call us, we'll call you".