Padrão Adapter
Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 95 de 110.
O padrão Adapter permite que interfaces incompatíveis trabalhem juntas. Ele atua como uma ponte entre duas classes que, de outra forma, não poderiam colaborar, envolvendo uma classe existente com uma nova interface que os clientes esperam. Isso é particularmente útil ao integrar bibliotecas de terceiros ou código legado em sua aplicação.
Imagine que você tem um sistema que trabalha com dados JSON, mas precisa integrar um componente que apenas gera XML. Em vez de modificar qualquer uma das classes, você cria um adaptador que traduz entre eles:
// Interface existente que seu sistema espera
abstract class JsonData {
String getJson();
}
// Classe legada com interface incompatível
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// O Adapter torna o XmlService compatível com JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// Converte XML para JSON (simplificado)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}O XmlToJsonAdapter envolve o XmlService e implementa a interface JsonData. O código do cliente trabalha com a familiar interface JsonData sem saber que os dados vieram originalmente de uma fonte XML. O adaptador lida com toda a tradução internamente.
Use o padrão Adapter quando você quiser usar uma classe existente, mas sua interface não corresponde ao que você precisa, ou quando você precisa criar uma classe reutilizável que coopere com classes que possuem interfaces incompatíveis.
Desafio
FácilVamos construir um sistema adaptador de reprodutor de mídia! Imagine que você tem um sistema de áudio moderno que espera que todas as fontes de mídia forneçam áudio por meio de uma interface padrão, mas você precisa integrar um antigo toca-discos de vinil que tem uma maneira completamente diferente de produzir som.
Você criará dois arquivos para organizar sua implementação do padrão adapter:
media_adapter.dart: Este arquivo contém sua interface e as classes do adaptador. Defina uma classe abstrataAudioSourceque seu sistema moderno espera - ela deve ter um métodoString playAudio()que retorna a saída de áudio como uma string. Em seguida, crie uma classeVinylPlayerrepresentando o equipamento legado - ela possui um campotrackNamee um métodoString spinRecord()que retorna*crackle* Playing vinyl: [trackName] *crackle*. Por fim, construa umVinylAdapterque implementaAudioSourcee envolve umVinylPlayer. O métodoplayAudio()do adaptador deve chamar o métodospinRecord()do toca-discos de vinil e retornar o resultado - fazendo a ponte entre as interfaces incompatíveis.main.dart: Importe seu arquivo de adaptador de mídia e demonstre como o adaptador faz o antigo toca-discos de vinil funcionar com o código que espera a interface modernaAudioSource. Crie umVinylPlayercom o nome da faixaBohemian Rhapsody. Em seguida, crie umVinylAdapterque envolva este toca-discos de vinil. Armazene o adaptador em uma variável do tipoAudioSourcepara provar que ele está em conformidade com a interface esperada. ChameplayAudio()em sua fonte de áudio e imprima o resultado.
A beleza deste padrão é que seu código principal funciona com a interface padrão AudioSource - ele não precisa saber que, nos bastidores, um antigo toca-discos de vinil está fazendo o trabalho real!
Saída esperada:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*Folha de consulta
O padrão Adapter permite que interfaces incompatíveis trabalhem juntas, agindo como uma ponte entre duas classes que, de outra forma, não poderiam colaborar.
O adapter envolve uma classe existente com uma nova interface que os clientes esperam, tornando-o útil ao integrar bibliotecas de terceiros ou código legado.
Estrutura Básica
// Interface alvo que os clientes esperam
abstract class JsonData {
String getJson();
}
// Classe existente com interface incompatível
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// O Adapter torna o XmlService compatível com JsonData
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// Converte XML para JSON
return '{"name": "John"}';
}
}Uso
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}O adapter implementa a interface alvo enquanto envolve a classe incompatível. O código do cliente trabalha com a interface familiar sem conhecer a implementação subjacente.
Quando usar: Quando você precisa usar uma classe existente, mas sua interface não corresponde ao que você precisa, ou ao criar uma classe reutilizável que coopera com classes que possuem interfaces incompatíveis.
Experimente você mesmo
import 'media_adapter.dart';
void main() {
// TODO: Crie um VinylPlayer com o nome da faixa "Bohemian Rhapsody"
// TODO: Crie um VinylAdapter que envolva o vinyl player
// TODO: Armazene o adaptador em uma variável do tipo AudioSource
// TODO: Chame playAudio() em sua fonte de áudio e imprima o resultado
}
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 ExternosBibliotecas e ImportaçõesIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosVariáveis de InstânciaFundamentos de ConstrutoresRecapitulação - Calculadora Simples4Null Safety
Introdução ao Null SafetyNullable vs Non-NullableOs Operadores ? e !Palavra-chave Late e Null SafetyOperadores Null-AwareNull Safety em ClassesRecapitulação - Sistema de Perfil de Usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementando vs EstendendoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Generics
Visão Geral de List, Set e MapColeções Type-SafeClasses GenéricasMétodos GenéricosRestrições de GenericsIterable e IteratorRecapitulação - Armazenamento Genérico13Conceitos Avançados de POO
Composição vs HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário2Construtores em Dart
Construtor PadrãoConstrutores NomeadosListas de InicializaçãoConstrutores ConstantesConstrutores FactoryConstrutores de RedirecionamentoRecapitulação - Shape Builder5Encapsulamento
Membros Públicos vs PrivadosA Convenção do Prefixo _Privacidade em Nível de BibliotecaAprofundamento em Getters & SettersOcultação de InformaçãoRecapitulação - Registros de Estudantes8Mixins
Introdução aos MixinsCriando MixinsUsando Múltiplos MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema Animal11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode & ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs EstáticosCampos Final & ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Conta Bancária6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodoA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do PolimorfismoPolimorfismo via InterfacesVerificação de Tipos em Tempo de ExecuçãoOs Operadores is & asPalavra-chave CovariantRecapitulação - Processador de Pagamentos12POO Assíncrona
Futures e async/awaitFundamentos de StreamsStream ControllersConstrutores AssíncronosAsync em Métodos de ClasseRecapitulação - Data Fetcher15Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository