Padrão Adapter
Parte da seção Programação Orientada a Objetos do Journey de PHP da Coddy — lição 76 de 91.
O Padrão Adapter é um padrão de projeto estrutural que permite que objetos com interfaces incompatíveis trabalhem juntos. Ele atua como uma ponte entre duas interfaces, traduzindo chamadas de um formato para outro.
Imagine que você está construindo uma aplicação que processa pagamentos e precisa integrar uma biblioteca de pagamentos de terceiros. A biblioteca funciona perfeitamente, mas sua interface não corresponde ao que seu código espera. Em vez de reescrever toda a sua aplicação, você cria um adaptador que faz a tradução entre as duas.
<?php
// A interface que sua aplicação espera
interface PaymentProcessor {
public function pay(float $amount): string;
}
// Biblioteca de terceiros com uma interface diferente
class StripeAPI {
public function createCharge(int $cents, string $currency): string {
return "Charged {$cents} {$currency} via Stripe";
}
}
O adaptador implementa a interface esperada enquanto utiliza internamente a classe de terceiros:
<?php
class StripeAdapter implements PaymentProcessor {
public function __construct(private StripeAPI $stripe) {}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->createCharge($cents, 'USD');
}
}
$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
Saída:
Charged 2999 USD via StripeO adaptador converte dólares em centavos e chama o método apropriado. O código da sua aplicação conhece apenas o PaymentProcessor, permanecendo alegremente alheio aos requisitos específicos do Stripe. Se você mudar posteriormente para um provedor de pagamento diferente, basta criar um novo adaptador sem alterar o código existente.
Desafio
FácilVamos construir um sistema de conversão de temperatura usando o Adapter Pattern. Você tem um sensor de temperatura legado que fornece leituras em Fahrenheit, mas sua aplicação meteorológica moderna espera todas as temperaturas em Celsius. Em vez de modificar qualquer um dos sistemas, você criará um adaptador que preenche essa lacuna.
Você organizará seu código em quatro arquivos:
TemperatureSensor.php— Defina uma interfaceTemperatureSensorque sua aplicação meteorológica espera. Ela deve ter um métodogetTemperature(): floatque retorna a temperatura em Celsius.LegacySensor.php— Crie uma classeLegacySensorque simula o hardware antigo. Esta classe possui uma interface diferente da que sua aplicação precisa:- Ela recebe uma leitura em Fahrenheit em seu construtor (use promoção de construtor)
- Ela possui um método
readFahrenheit(): floatque retorna o valor em Fahrenheit armazenado
LegacySensorAdapter.php— Inclua tanto a interface TemperatureSensor quanto a classe LegacySensor. Crie uma classeLegacySensorAdapterque implementaTemperatureSensore envolve umLegacySensor. Seu adaptador deve:- Aceitar um
LegacySensorem seu construtor - Implementar
getTemperature()lendo o valor em Fahrenheit do sensor legado e convertendo-o para Celsius usando a fórmula:(fahrenheit - 32) * 5 / 9
- Aceitar um
main.php— Inclua o arquivo LegacySensorAdapter. Você receberá uma entrada: uma temperatura em Fahrenheit.Crie um
LegacySensorcom a temperatura de entrada e, em seguida, envolva-o em umLegacySensorAdapter. ChamegetTemperature()no adaptador e imprima o resultado arredondado para duas casas decimais.O formato de saída deve ser:
Temperature: [celsius]C
Este desafio demonstra como o Adapter Pattern permite integrar interfaces incompatíveis sem modificar o código existente. Sua aplicação meteorológica trabalha exclusivamente com a interface TemperatureSensor, completamente alheia ao fato de que as leituras reais vêm de um sensor Fahrenheit legado.
Folha de consulta
O Adapter Pattern (Padrão Adaptador) é um padrão de projeto estrutural que permite que objetos com interfaces incompatíveis trabalhem juntos, agindo como uma ponte entre eles.
Estrutura Básica
Defina a interface que sua aplicação espera:
<?php
interface PaymentProcessor {
public function pay(float $amount): string;
}Uma classe de terceiros com uma interface diferente:
<?php
class StripeAPI {
public function createCharge(int $cents, string $currency): string {
return "Charged {$cents} {$currency} via Stripe";
}
}Criando o Adaptador
O adaptador implementa a interface esperada enquanto utiliza internamente a classe de terceiros:
<?php
class StripeAdapter implements PaymentProcessor {
public function __construct(private StripeAPI $stripe) {}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->createCharge($cents, 'USD');
}
}Uso
$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
// Saída: Charged 2999 USD via StripeO adaptador traduz entre interfaces, permitindo que o código da sua aplicação permaneça inalterado ao integrar bibliotecas de terceiros ou trocar implementações.
Experimente você mesmo
<?php
require_once 'LegacySensorAdapter.php';
// Ler entrada
$fahrenheit = floatval(trim(fgets(STDIN)));
// TODO: Criar um LegacySensor com a temperatura de entrada
// TODO: Envolvê-lo em um LegacySensorAdapter
// TODO: Chamar getTemperature() no adaptador
// TODO: Imprimir o resultado arredondado para duas casas decimais
// Formato de saída: Temperature: [celsius]C
?>Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de POO
Arquivos ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave $thisMétodosPropriedadesConstrutor (__construct)Destrutor (__destruct)Recapitulação - Calculadora Simples4Herança
Herança BásicaA Palavra-chave parent::Sobrescrita de MétodoA Palavra-chave finalClasses AbstratasRecapitulação - Hierarquia de Funcionários7Encapsulamento
Público, Protegido, PrivadoModificadores de Acesso em DetalhesGetters e SettersOcultação de InformaçãoPromoção de Construtor (8.0)Recapitulação - Sistema de Registro de Alunos10Conceitos Avançados de POO
Composição vs HerançaInjeção de DependênciaClasses AnônimasEnums (PHP 8.1)Fibers (PHP 8.1)Mergulho Profundo em Clonagem de ObjetosGeradores e Iteradores13Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository2Namespaces e Autoloading
Introdução a NamespacesA Palavra-chave usePadrão de Autoloading PSR-4Autoloader do ComposerRecapitulação - Projeto Organizado5Interfaces e Contratos
Introdução a InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesInterface vs Classe AbstrataType Hinting com InterfacesRecapitulação - Calculadora de Formas8Métodos Mágicos
Introdução aos Métodos Mágicos__toString e __debugInfo__get, __set, __isset, __unset__call e __callStatic__clone e Clonagem de Objetos__serialize e __unserializeRecapitulação - Coleção Personalizada11Sistema de Tipos e Tratamento de Erros
Declarações de TiposTipos AnuláveisTipos de União e InterseçãoClasses de ExceçãoHierarquia de Exceções PersonalizadasTry, Catch, FinallyRecapitulação - Validador de Formulário14Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário3Propriedades de Classe
Propriedades de Instância vs EstáticasConstantes em ClassesMétodos e Propriedades EstáticosPropriedades Privadas e ProtegidasPropriedades Readonly (PHP 8.1)Recapitulação - Gerenciador de Conta Bancária6Polimorfismo
Sobrescrita de Métodos RevisitadaPolimorfismo via InterfacesType Hinting e Union TypesLate Static BindingRecapitulação - Processador de Pagamentos9Traits
Introdução a TraitsUsando Múltiplos TraitsResolução de Conflitos de TraitsMétodos Abstratos em TraitsTraits vs Herança12Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy