terça-feira, 30 de março de 2010

Design Pattern Template Method, aumente sua produtividade

Salve salve, leitor.

Durante minha busca sobre Design Patterns (padrões de projeto) e técnicas avançadas sobre desenvolvimento, experimentei diversos Design Patterns, alguns muito específicos e outros bem práticos para o uso no dia-a-dia.

Este é um Design Pattern muito útil para agilizar o desenvolvimento de tarefas rotineiras.


O Template Method consiste na criação de um algoritmo com partes fixas e partes variáveis.




As partes fixas do algoritmo ficam em uma superclasse abstrata que faz o uso de métodos abstratos.

Os métodos abstratos, por sua vez, são implementados em subclasses que adicionam comportamento específico (parte variável) para esta parte do algoritmo.

Os métodos da classe abstrata que fazem uso dos métodos abstratos são chamados de Template Method, já os métodos abstratos são chamados de operações primitivas.

Em outras palavras, o Template Method proporciona o reuso de algoritmos utilizado por duas ou mais classes que são muito parecidas.

Definição do padrão


  1. Intenção

    Definir o esqueleto de um algoritmo em uma operação, deixando alguns passos para subclasses clientes. Template Method permite que subclasses redefinam determinadas etapas de um algoritmo sem alterar a estrutura do algoritmo. A classe base declara espaços (placeholders) no algoritmo, e as classes derivadas implementar os espaços (placeholders) reservados.



  2. Problema

    Dois componentes diferentes apresentam semelhanças significativas, mas não demonstram a reutilização da interface comum ou de execução. Se uma alteração é comum a ambos os componentes, torna-se necessário esforço maior devido ausência do reuso.



  3. Discussões

    O desenvolvedor do componente decide quais os passos de um algoritmo são invariáveis (ou padrões), e que são variantes (ou personalizáveis). As etapas invariantes são implementadas em uma classe base abstrata, enquanto as medidas variantes são definidas como métodos ganchos (hooks) na classe base. As etapas variantes representam ganchos (hooks), ou espaços (placeholders), que podem ou devem ser fornecidos pelo cliente do componente de uma classe concreta derivada.

    O desenvolvedor do componente define os passos necessários de um algoritmo e a ordenação das etapas, mas permite ao componente cliente alterar ou substituir algumas etapas.


Exemplo da implementação sem o uso Template Method

Classe CrudCliente class CrudCliente{ public function insert(array $bind = array()){ $table = new ClienteTable(); //outros comandos que se repetem en todas as classes cruds .. $table->insert($bind); } /** * @return array of rows */ public function fetchAll($condition = null){ $table = new ClienteTable(); $rowset = $table->fetchAll($condition); $return = array(); foreach($rowset as $row){ $return[] = $row; } return $return; } /* Outros métodos, update, delete, etc.. */ .. } Classe CrudFuncionario class CrudFuncionario{ public function insert(array $bind = array()){ $table = new ClienteTable(); //outros comandos que se repetem en todas as classes cruds .. $table->insert($bind); } /** * @return array of rows */ public function fetchAll($condition = null){ $table = new ClienteTable(); $rowset = $table->fetchAll($condition); $return = array(); foreach($rowset as $row){ $return[] = $row; } return $return; } /* Outros métodos, update, delete, etc.. */ .. }

Repare que os métodos insert's das classes Crudfuncionário e CrudCliente, com excessão a classe de tabela que eles utilizam, são idênticos.

Com base nisto podemos criar uma classe base abstrata e adicionar um método abstrato que retorna uma classe table que precisamos para cada caso e todo o resto do algoritimo pode ser mantido na classe abstrata para evitar repetição de código.

Exemplo da implementação do Template Method

Classe Abstrata <?php class CrudAbstract{ /* método abstrato que será implementado na subclasse */ public abstract function getTable(); /** * @return array of rows */ public function fetchAll($condition = null){ /* Chamada do método abstrato que será implementado na subclasse */ $table = $this->getTable(); $rowset = $table->fetchAll($condition); $return = array(); foreach($rowset as $row){ $return[] = $row; } return $return; } public function insert(array $bind = array()){ /* Chamada do método abstrato que será implementado na subclasse */ $tableObject = $this->getTable(); /* Rotinas fixas do algorítmo */ ... return $tableObject->insert($bind); } /* Demais metodos update, delete etc.. */ ... ... } Subclasses Concretas : class CrudCliente extends CrudAbstract{ /* Implementação do método abstrato */ public function getTable(){ return new ClienteTable(); } } class CrudFuncionario extends CrudAbstract{ /* Implementação do método abstrato */ public function getTable(){ return new FuncionarioTable(); } } /* Utilização da classe concreta, chamando o método fetchAll que é um template method */ $funcionario = new CrudFuncionario(); $funcionario->fetchAll('nome = "reinaldo"');

O exemplo acima mostra como os códigos que antes eram implementados em duas diferentes classes, deram origem a três classes, uma abstrata que contém o(s) Template(s) Method(s), duas classes abstratas que implementam as operações primitivas ou ganchos(hooks).

O fluxo de execução do algoritmo é controlado pela classe abstrata e este processo é chamado de inversão de controle, pois ao invés da classe em questão utilizar recursos da superclasse é a superclasse que utiliza recursos da subclasse. Isto também é conhecido como Hollywood Principle (princípio de hollywood) que diz: Don't call us, we call you (Não nos chame, te chamaremos).

Este princípio é amplamente utilizado por Frameworks para aumentar a produtividade diminuindo a complexidade das implementações rotineiras.

Conclusão

  • A utilização do Design Pattern Template Method traz grandes benefícios, pois reduz a duplicidade de operações semelhantes (reutilização), e isto traz uma vantagem muito grande na manutenção, pois um bug descoberto na superclasse implica em uma alteração somente na superclasse e todos os pontos do sistema estarão corrigídos.
  • Trata-se de um Design Pattern bastante simples porém muito poderoso e seu uso no dia-a-dia traz benefícios claros para o desenvolvimento.
  • É amplamente utilizado pela maioria (se não todos) Frameworks de desenvolvimento existentes no mercado.


Referências:

Nenhum comentário:

Postar um comentário