Matheus Tardivo

Code is poetry.

Don’t Call Us, We’ll Call You.

O padrão Template Method define o esqueleto de um algoritmo dentro de um método transferindo alguns de seus passos para as subclasses. O Template Method permite que as subclasses redefinam certos passos de um algoritmo sem alterar a estrutura do próprio algoritmo.

Basicamente, o padrão consiste na criação de um template para o algoritmo. Mas o que é um template? É apenas um método – ou, mais especificamente, é um método que define um algoritmo como uma seqüência de passos. Um ou mais desses passos podem ser definidos como abstratos e implementados por uma subclasse. Isto assegura que a estrutura do algoritmo permaneça inalterada mesmo quando as subclasses fornecem parte da implementação.

Verifiquemos o diagrama de classes:

  • A ClasseAbstrata contém o template method e versões abstratas das operações usadas no template method.
  • O template method utiliza operações primitivas para implementar um algoritmo, mas desconectada da implementação efetiva dessas operações.
  • A ClasseConcreta implementa as operações abstratas, que são chamadas quando o templateMethod() precisa delas.
  • Podem existir muitas classes concretas, cada uma implementando o conjunto de operações exigidas pelo template method.

E o código: ClasseAbstrata

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public abstract class ClasseAbstrata {

  public final void templateMethod() {
      operacaoPrimitiva1();
      operacaoPrimitiva2();
      operacaoConcreta1();
      operacaoConcreta2();
  }

  public abstract void operacaoPrimitiva1();

  public abstract void operacaoPrimitiva2();

  public void operacaoConcreta1() {
      // implementação
  }

  public void operacaoConcreta2() {
      // implementação
  }
}

ClasseConcreta

1
2
3
4
5
6
7
8
9
10
public class ClasseConcreta extends ClasseAbstrata {

  public void operacaoPrimitiva1() {
      // implementação da operação primitiva 1
  }

  public void operacaoPrimitiva2() {
      // implementação da operação primitiva 1
  }
}

Usando:

1
2
ClasseAbstrata classe = new ClasseConcreta();
classe.templateMethod();

Uma forma de controle das extensões de subclasses são os métodos gancho (hook methods, em inglês). É possível então criar um template method que chama os métodos gancho, permitindo um controle do comportamento somente nestes pontos.

Agora um código de exemplo usando o gancho:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class ClasseAbstrata {

  public final void templateMethod() {
      // Agora a operação está condicionada ao gancho.
      if (gancho()) {
          operacaoPrimitiva1();
      }
      operacaoPrimitiva2();
      operacaoConcreta1();
      operacaoConcreta2();
  }

  public abstract void operacaoPrimitiva1();

  public abstract void operacaoPrimitiva2();

  public void operacaoConcreta1() {
      // implementação
  }

  public void operacaoConcreta2() {
      // implementação
  }

  // Por padrão, o gancho apenas retorna true.
  public boolean gancho() {
      return true;
  }
}

As subclasses podem ou não sobrescrever o gancho. Devem fazer isso apenas se desejam mudar o comportamento padrão, como por exemplo, adicionar alguma condição para a execução da operacaoPrimitiva1. Exemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ClasseConcreta extends ClasseAbstrata {

  public void operacaoPrimitiva1() {
      // implementação da operação primitiva 1
  }

  public void operacaoPrimitiva2() {
      // implementação da operação primitiva 1
  }

  @Override
  public boolean gancho() {
      // Faz alguma verificação
      if (...) {
          return true;
      }

      return false;
  }
}

Mas você deve estar se perguntando: “O que o título deste post tem haver com esse padrão?”. A resposta é simples: muito! Este título é o Princípio de Hollywood, que traduzido significa: Não nos telefone, nós telefonaremos para você.

O Princípio de Hollywood nos proporciona uma maneira de evitar o “colapso das dependências”. Colapso das dependências é o que acontece quando você tem componentes de alto nível dependendo de componentes de baixo nível que dependem de componentes de alto nível que dependem de componentes laterais que dependem de componentes de baixo nível, e assim por diante (ufa). Quando essa estrutura entra em colapso, ninguém mais consegue entender como o sistema foi originalmente projetado.

Com o Princípio de Hollywood, nós permitimos que componentes de baixo nível se conectem ao sistema através de ganchos, mas são os componentes de alto nível que determinam quando e como eles serão solicitados. Em outras palavras, os componentes de alto nível dizem aos componentes de baixo nível: “Não nos telefone, nós telefonaremos para você.”

É provável que você já tenha detectado a conexão entre o Princípio de Hollywood e o Template method: quando usamos um template method, na verdade estamos dizendo às subclasses: “não nos telefone, nós telefonaremos para vocês”.

Don’t Talk to Strangers

A Lei de Deméter ou o Princípio do Mínimo Conhecimento nos orienta a reduzir as interações entre objetos, limitando-as a apenas alguns “amigos” mais próximos.

No projeto de um sistema, você deve tomar cuidado com o número de classes com que qualquer objeto interage e também com a forma como essa interação ocorre.

Este princípio nos orienta a não criar projetos com um grande número de classes interconectadas, o que faz com que qualquer alteração numa parte do sistema exerça um efeito em cascata sobre outras partes. Um sistema com muitas dependências entre múltiplas classes é um sistema frágil, de difícil manutanção e complexo demais para ser compreendido por outros.

O princípio nos fornece algumas dicas: pegamos um objeto qualquer e, a partir de qualquer método nesse objeto, só podemos invocar métodos quer pertençam:

  • Ao próprio objeto
  • A objetos que tenham sido passados como parâmetro para o método
  • A qualquer objeto que seja criado ou instanciado pelo método
  • A quaisquer componentes do objeto - Pense em “componente” como qualquer objeto que seja referenciado por uma variável de instância. Em outras palavras, esta seria uma relação TEM-UM.

Um exemplo:

Sem o princípio:

1
2
3
4
public float getTemp() {
  Thermometer thermometer = station.getThermometer();
  return thermometer.getTemperature();
}

Com o princípio:

1
2
3
public float getTemp() {
  return station.getTemperature();
}

Em um outro exemplo:

1
String nomeFilial = funconario.getDepartamento().getFilial().getNome();

Caso você tenha que navegar muito nos seus objetos você está, provavelmente, com um problema na sua modelagem. Neste caso, talvez o que você teria que fazer seria delegar isso para uma classe de “meio de campo”.

O uso de Padrões de Projeto e outros Princípios OO ajudam na aplicação da Lei de Deméter.

Já que comentei sobre Padrões de Projeto e outros Princípios OO, vou listar abaixo alguns desses princípios:

  • Encapsule o que varia
  • Dê prioridade à composição em relação à herança
  • Programe para interface, não para implementações - Estratégia
  • Tente manter conexões flexíveis entre objetos que interagem.
  • As classes devem estar abertas para a extensão, mas fechadas para modificação.

E alguns padrões:

Claro que existem outros padrões que podem auxiliá-lo e, por isso, recomendo a leitura de livros sobre o assunto.

A Lei de Deméter é uma Rule of thumb e seu uso deve ser priorizado, mas, por diversos motivos, nem sempre podemos utilizá-la.

Embora o Princípio do Mínimo Conhecimento reduza as dependências entre objetos, e estudos tenham comprovado que isso simplifica a manutenção do software, sua aplicação também exige que mais classes “envelopadoras” sejam escritas para lidar com as chamadas de métodos em outros componentes. Isso pode aumentar a complexidade e o tempo de desenvolvimento do software, além de reduzir seu desempenho durante a execução.

Uma boa parte desse texto foi retirado do livro Head First Design Patterns que, com certeza, é uma ótima leitura.

Hello World!

Olá pessoal! Vou tentar escrever algo de útil aqui (assim que eu tiver um tempinho).

Pretendo começar colocando um artigo sobre Struts 2 + Spring 2 + JPA + AJAX. É uma praticamente o mesmo exemplo desse artigo, mas com algumas modificações e comentários.

Até mais.