Back-End

22 fev, 2008

Padrões de Projeto – Adapter

Publicidade

Salve, salve leitores do iMasters!

Há algum tempo estamos tratando com uma seqüência de artigos sobre Padrões de Projetos em PHP. Com o desenvolvimento de sistemas utilizando Orientação a Objetos (OO), surgiu no mercado um novo nicho: O Desenvolvimento de Frameworks Terceirizados.

Uma das vantagens da utilização do Paradigma OO é a reutilização de código. Isso nos poupa um tempo precioso e evita que “sempre reinventemos a roda” permitindo que utilizemos soluções prontas para determinado problema.

Mas existe um inconveniente nessa abordagem!

Como iremos proteger nossas aplicações de mudanças dos frameworks externos? Como atualizar nossos códigos, submetendo-nos às modificações necessárias nas bibliotecas de terceiros?

É nesse contexto que utilizamos o Padrão de Projeto Adapter.

Nome do Padrão: ADAPTER

Problema: Como enfrentar modificações de bibliotecas terceirizadas, mantendo nossa aplicação sincronizada quanto às alterações essenciais nas funcionalidade e arquitetura.

Solução: Utilizando classes que trabalharão na camada intermediária entre a aplicação cliente e a biblioteca em si. Executando alterações quanto às chamadas de operações para uma correta operação.

Utilizemos um exemplo simples.

Imagine que utilizamos uma classe utilitária de um framework especializado em métodos para programadores iniciantes:

Chamaremos essa classe de UtilLib:

class UtilLib {

/**
Esse metodo será "depreciated" no futuro
*/
function alo() {
return "Alô ";
}

function mundo() {
return "Mundo!";
}
}

Na documentação da classe, o método alo() será depreciado (sem utilização) no futuro.

Digamos que em versões subseqüentes da classe UtilLib sejam lançadas e o método alo() tenha sido retirado definitivamente.

Como poderemos utilizar a nova versão da classe UtilLib em nossa aplicação “legada”, que utiliza o antigo método alo() (agora excluído)??

Se apenas substituímos a classe em nossa aplicação, será disparado um erro, afirmando que está sendo feito uma chamada que não existe. E agora?

O Padrão Adapter entra em ação!

Existe duas formas para implementar o Padrão Adapter:

  1. Criamos uma classe intermediaria que servirá como interface entre as chamadas do código cliente e o código da classe. Ele trabalhará basicamente como um “filtro” para as chamadas. Chamamos essa forma de COMPOSIÇÃO.
  2. Criamos uma classe que HERDARÁ da classe utilitária e sobrescrevemos ou recriamos o método chamado. Chamamos essa forma de HERANÇA.

A escolha da abordagem de implementação do Adapterserá uma tomada de decisão do Arquiteto de Software e dependerá do contexto da aplicação. Muita cautela nessa hora!

O Diagrama de Classes abaixo explicita as duas formas:

Diagrama de Classes - ComposiçãoDiagrama de Classes – Composição

Diagrama de Classes - HerançaDiagrama de Classes – Herança

Vamos a uma implementação…

Note que no Diagrama de Classes, utilizamos a versão mais recente da classe UtilLib, sem o método alo() e inclusão do método hello().

Primeiro a classe UtilLib;


class UtilLib {
  
    public  function __construct() {
        
    }
    public  function hello() {
        return "Alô  ";
    }

    public  function mundo() {
        return "Mundo! ";
    }

}

Nessa classe apenas excluímos o método alo() e criamos o método hello();

Criamos a classe ClasseAdapter_Composicao criando em seu construtor a classe UtilLib e readaptando nossos métodos.

class ClasseAdapter_Composicao {
     private biblioteca;
    public  function __construct() {
        $this->biblioteca = new UtilLib();//Instaciando a biblioteca
    }
    public  function alo() {
        return $this->biblioteca->hello();//Readaptando a chamada para o método da biblioteca
    }

    public  function mundo() {
        return $this->biblioteca->mundo();
    }

}

Note que a classe ClasseAdapter_Composicao realmente funciona como um intermediário, filtrando e readaptando as chamadas à classe UtilLib;

Implementamos agora a classe ClasseAdapter_Herança.

class ClasseAdapter_Heranca  extends UtilLib{

    public  function __construct() {
	parent::__construct();
    }
    public  function alo() {
        return $this-> hello();//Readaptando a chamada para o método da biblioteca herdada
    }

    public  function mundo() {
        return $this->mundo();
    }

}

Particularmente, prefiro essa forma de implementação do Padrão Adapter. O motivo é que dessa forma, poderíamos substituir de forma transparente qualquer referencia da classe antiga UtilLib por essa classe. Ou seja, na aplicação cliente, onde existisse a utilização da classe UtilLib, trocaríamos por ClasseAdapter_Heranca mantendo a coesão da aplicação.

Essa funcionalidade não é perceptível na linguagem PHP, pois ela é tida como uma linguagem fracamente tipada, mas saliento que os Padrões de Projeto são desenvolvidas para serem implementadas em QUALQUER linguagem Orientada a Objetos.

A classe Cliente, descrita abaixo, representa a classe que utilizará a biblioteca através de nossas classes Adapter.

class Cliente {

    public  function __construct() {
	//Codigo Antigo - Esse código utiliza a antiga versão da UtilLib
	$lib = new UtilLib();
	echo $lib->alo() . $lib->mundo();
		
	//Novo Código - Forma Composição, Usar Versão nova de UtilLib
	$lib1 = new ClasseAdapter_Composicao();
	echo $lib1->alo() . $lib1->mundo();

	//Novo Código - Forma Herança, Usar Versão nova de UtilLib
	$lib2 = new ClasseAdapter_Heranca();
	echo $lib2->alo() . $lib2->mundo();

    }

}

Abraços e sucesso a todos!