Padrão de Projeto – Adapter


Imagine um mundo bem simples, sem requisitos solicitando alteração da aplicação. Sem inovações. Programar seria simples, mas bem chato. Programadores continuarão a criar aplicativos em cima das melhores tecnologias de 10 anos atrás. Eles nunca terão de introduzir diferentes bases de dados, implementação de novas práticas, ou consumir APIs diferentes.
Mas isso foi só um sonho, ou melhor um pesadelo, as coisas mudam, e muito. Felizmente, os programadores têm o Adapter Design Patttern para ajudar a atualizar sistemas legado com o novo código e funcionalidade.

Nome: Adapter

O Design Patter Adapter simplesmente adapta interface entre um objeto para o que o outro objeto que espera.

Problema e Solução

Em um aplicativo, você pode ter uma aplicação estável e bem arquitetada. No entanto, a nova funcionalidade requer o uso de objetos existentes em uma maneira diferente do que eles foram originalmente concebidos. A alteração pode ser tão simples como alterar o nome da função para a nova  funcionalidade. Também poderia ser um pouco mais complexo cenário, onde a funcionalidade espera um comportamento ligeiramente diferente objeto original.

A solução é a construção de um outro objeto, usando o Adapter Design Pattern. Este objeto Adapter funciona como intermediário entre o aplicativo orignal e novas funcionalidades. O Adapter Design Pattern define uma nova interface para um objeto existente para corresponder ao que o novo objeto requer.

Para a maior parte do sistema, nenhuma funcionalidade existente está perdida, só será usada ou consumida de uma maneira diferente. Você pode comparar isso a um adaptador elétrico, que recebe uma ligação de três pinos aterrada e altera o padrão para um socket de dois pinos. O Adapter Design Pattern visa ajudar OPP, que cria as conversões para as interfaces do objeto. Embora possa ser tentador para modificar o código existente para trabalhar no modo que a nova funcionalidade espera, você deve criar um adaptador de objeto em seu lugar. Muitas vezes, sugere-se que um ajuste rápido de um objeto existente é a mais rápida e de custo efetivo para realizar essa tarefa. Defendo que a velocidade e os custos são raramente um problema ao criar o objeto do adaptador. Nenhuma nova funcionalidade real está sendo criado, até o momento o objeto original foi alterado e testado contra a regressão, uma classe do adaptador rápida com poucas linhas de código poderia ter sido criado sem possibilidade para a regressão.

A melhor solução ainda é a de criar um objeto adaptador. Esta favorece a possibilidade de evolução paralela de ambos e as novas funcionalidades da base de código existente. Se seu trabalho é integrar a funcionalidade nova, e você vai fazer isso editando a código existente, você provavelmente encontrará em desacordo com a equipe que está desenvolvendo novas funcionalidades nas classes originais. Eles podem ter adicionando outros métodos particulares e expecptions que  sejam chamados pelos métodos públicos que foram inicialmente disponível com a última versão estável. A última coisa que você quer é criar um cenário de fusão complexo ou uma base de código bifurcada.

Adaptador Design Pattern é também uma excelente solução para as alterações a uma fonte de dados. Dois problemas comuns alterações dizem respeito quando o bando de dados muda e arquivo de acesso são alterações:

– O projeto pode necessitar de alterar o mecanismo de banco de dados para N número de razões. Um cenário comum envolve uma aplicação criada com o MySQL a migração para um grande banco de dados como Oracle. Outro caso pode ser uma restrições de licença por conta dos custos consequentemente exige um banco de dados diferente, por exemplo, Postgres, e isso tudo quando o produto finalmente vai para produção. Se você não estiver usando uma camada de abstração de banco de dados, você precisará criar um objeto Adapter interceptar as chamadas de funções relacionadas a banco de dados legado e fazer aqueles compatíveis com o novo banco de dados. Curiosamente, se você examinar o código de algumas bibliotecas de abstração de dados, você vai vêr nada mais que uma coleção de adaptadores também.

– Ao trabalhar com uma terceira fonte de informação, os dados dessa fonte podem alterar o formato. Seu fornecedor pode estar trabalhando os dados no formato CSV durante anos, mas vai migrar para um documento XML. O adaptador pode ser criado e ele irá consumir o XML e retornar um formato do CSV já conhecido pelo sistema atual.

Basicamente, sempre que houver um problema que exige alterar o padrão da plataforma principal e não interromper o fluxo da aplicação existente, o Design Pattern Adapter pode ser usado no desenvolvimento da solução.

UML

Esta “Unified Modificado Language” (UML) que detalha um diagrama de classe do Design Pattern Adapter a partir de um exemplo de um rádio automotivo ser utilizado em dois tipos de automóveis, Civic e o Logan.

Design Pattern Adapter - Exemplo do Rádio AutomotivoExemplo de Design Pattern

Note que flui sobre esta figura:
– A classe “RadioDoCivic” contém um método chamado alterarVolume(). “Civc” tem uma instância do “RadioDoCivic” e solicita alterarVolume() durante a chamada da função upSound().
– A classe “Logan” é o novo objeto que precisa utilizar o mesmo “RadioDoCivic”. Sua função variarSom() chama um método público da instância “RadioDoCivic” chamado maisVolume() durante a execução.
– O “RadioDoCivicAdapterParaLogan” é criado por estender a classe “RadioDoCivic”. Em seguida, ele fornece um método público chamado maisVolume() conforme o esperado pelo “Logan”. Neste exemplo simples, o maisVolume() faz é chamar alterarVolume().

Exemplo prático

Na base de código original do projeto, existe um objeto que manipula todas as mensagens de erro e códigos chamados errorObject. Os programadores originais não pensam que o código jamais iria gerar algum erro, por isso projetamos o sistema para enviar as informações de erro errorObjects diretamente ao console.

Neste exemplo, uma mensagem 404: Not Found de erro está sendo gerado. Eles estão supondo que o conteúdo da mensagem de erro e código pode mudar, mas o texto vai ficar sempre no mesmo formato.

<?php

class errorObject {

private $__erro;

public function __construct ($erro) {

$this->__erro = $erro;

}

public function getErro() {

return $this->__erro;

}

class logToConsole {

private $__errorObject;

public function __construct ($errorObject) {

$this->__errorObject = $errorObject;

}

public function escrever() {

fwrite(STDERR, $this->__errorObject->getError());

}

}

?>

Neste cenário, uma nova equipe de admin foi trazido ao projeto. As melhores práticas sugerem que um log de ​​rede para sftware monitorização devem ser instalados. O pacote requer que o administrador escolham os erros que devem ser registrados em um arquivo CSV com várias colunas. O formato CSV terá duas colunas, a primeira será o código de erro e a segunda a mensagem de erro.

Este novo pacote de software é parecido com a classe errorObject. O fornecedor disponibilizou o código que gera registra os logs no formato correto! Infelizmente, esse código foi criado a partir de uma versão diferente do errorObject que o projeto atual está usando. O errorObject novo tinha dois outros métodos públicos, a chamada getErrorNumber() e getErrorText() que a classe logToCSV espera para usá-los.

<?php

class logToCSV {

const CSV_LOCALIZACAO = ‘log.csv’;

private $__errorObject;

public function __construct ($errorObject) {

$this->__errorObject = $errorObject;

}

public function escrever (){

$linha = $this->__errorObject->getErrorNumber();

$linha .= ‘,’;

$linha .= $this->__errorObject->getErrorText();

$linha .= “\n”;

file_put_contents(self::CSV_LOCALIZACAO, $linha, FILE_APPEND);

}

}

?>

Existem duas soluções para esse problema:

  • Alterar o código original do errorObject
  • Criar um objeto Adaptet

Como precisamos manter as interfaces publicas do errorObject, a criação de um Adapter é a melhor solução.

No objeto adapter que iremos criar, precisamos manter todas as funções do errorObject e adicionar os métodos públicos gerErrorNumber() e o getErrorText() devem estar disponíveis. No sistema legado logToConsole, o método getError() é chamado para retornar a mensagem de erro. O Adapter deve fazer uso desse método para obter a mensagem de erro da classe herdada e , em seguida traduzir essa saída a ser usada pelos dois novos métodos getErrorNumber e getErrorText.

Design Pattern Adapter (errorObject)Exemplo de Design Pattern

<?php

class logToCSVAdapter extends errorObject {

private $__errorNumber, $__errorText;

public function __construct ($erro) {

parent::__construct ($erro) ;

$parts = explode(‘:’, $this->getErro());

$this->__errorNumber = $parts[0];

$this->__errorText = $parts[1];

}

public function getErrorNumber() {

return $this->__errorNumber;

}

public function getErrorText() {

return $this->__errorText;

}

}

?>

Finalmente, para implementar este Adapter, o novo código utiliza a instancia do Adapter ao invés do objeto original errorObject. Então a classe logToCSV pode conter a classe Adapter ao invés do errorObject original. A herança permite que o Adapter forneça o que o logToCSV necessite.

Um exemplo de como implementar utilizando o adapter pode ser visto logo abaixo:

<?php

$error = new logToCSVAdapter (“404:Not Found”);

$log = new logToCSV($error);

$log->write();

?>

Lembre-se de execução de um objeto Adapter é a melhor prática para evitar dor de cabeça quando a interface do objeto precisa ser traduzido para uso por outro.

Você pode seguir este artigo através do RSS 2.0 feed. Você pode deixar uma resposta, ou trackback do seu próprio site.

2 Comments »

 
  • Ismael Vacco disse:

    Bom artigo, Namba. Agora vc começa a me entender quando eu falo de designer patterns, frameworks, ORMs, etc.

  • Namba disse:

    Sempre te entendi, mas estou estudando e compartilhando para que todos possamos agregar com pontos de vista fundamentados de forma teórica e não somente em experiências passadas.

    Quero me fundamentar em processos, padrões e gestão de negociação, para não permitir que termos “eu acho”, “na minha opnião”, “quando trabalhei na empresa XPTO” leve o projeto ou o processo para um caminho tortuoso.

 

Deixe um Comentário

Time limit is exhausted. Please reload CAPTCHA.

*