Índice do grimório

Padrão 06 · Estruturais

Adapter

adaptar um fornecedor legado ao contrato esperado, incluindo conversão de velocidade.

Começar pelo código
Sarga coopera no reparo do farol, dirigindo uma chama estreita à crosta de pedra enquanto Iria e a equipe observam protegidos.
Cena do capítulo 06 · Adapter

01 · Entenda a escolha

Os fundamentos do padrão.

README.md

06 — Adapter: Integração de dragões legados

O cliente usa DragaoNovo, com velocidade em m/s e ataque que devolve resultado. DragaoAdapter compõe DragaoAntigo, converte km/h para m/s, traduz o alvo e o resultado de fogo, sem editar a biblioteca legada. Uma implementação nativa atende ao mesmo contrato diretamente.

Executar

Node 26.10.0, npm 11.19.1, TypeScript 5.9.3, @types/node 26.0.0, lock próprio. Dentro deste diretório:

npm ci --ignore-scripts
npm test
npm start
npm run solution

Da raiz Books:

node book-23/scripts/projetos.mjs 06 install
node book-23/scripts/projetos.mjs 06 check
node book-23/scripts/projetos.mjs 06 capture
node book-23/scripts/projetos.mjs 06 verify

O build limpa dist, usa tsc local estrito para ES2022/ESM e testa o JavaScript emitido com node:test. Não importa capítulos vizinhos. Tentativas em exercise/ ficam fora da compilação da resposta.

Papéis e arquivos

  • src/contratos.ts: Target DragaoNovo, pedido, resultado e erro de recurso indisponível.
  • src/legado/dragao-antigo.ts: Adaptee, biblioteca simulada que só oferece velocidade em km/h e fogo.
  • src/adapter.ts: Adapter por composição, com conversão numérica e delegação.
  • src/nativo.ts: implementação nativa do Target, sem camada de tradução.
  • src/cliente.ts: liberarRochaDoFarol(), cliente independente de fornecedor.
  • src/validacao.ts: valores de velocidade e alvo não vazio.
  • src/main.ts: mesmo cliente para nativo/adaptado e ordem sem equivalente recusada.
  • test/adaptacao.test.ts: conversão, contrato comum, chamadas delegadas, erros e fidelidade do resultado.
  • exercise/ e solution/: segundo fornecedor em nós, outro adaptador e testes.
  • diagram.mmd: fonte editável das relações do código-base; renderização e QA visual ficam na etapa própria.
  • evidence/: stdout real, testes, manifesto e execução em cópia isolada.

Contrato do cenário novo

O arquivo legado é uma biblioteca simulada para este livro, com unidade declarada em seu contrato. Não é reprodução literal do snippet do Medium: aquele exemplo devolvia 100 sem declarar uma unidade. A convenção de km/h e o resultado observável são parte desta reescrita; não se afirma que aquele 100 originalmente significava km/h.

O adaptador recebe a biblioteca e só usa suas operações públicas. voarVelocidade() retorna km/h; o adaptador divide por 3.6. soltarFogo(alvo) retorna {rocha, desobstruida}; o adaptador traduz para {alvo, efeito: 'fogo', rochaLiberada}. O campo booleano é preservado, inclusive quando o fornecedor relata false. O resultado é copiado e congelado, sem manter alias mutável do retorno legado.

DragaoNovo.atacar() permite pedir fogo ou gelo, com possibilidade contratual de lançar RecursoSemEquivalente quando o pacto não oferecer aquele efeito. Os dois fornecedores-base oferecem fogo e recusam gelo; não se inventa um equivalente. A recusa acontece antes de delegar a operação. Alvos vazios são rejeitados antes de chamar o legado. Exceções do fornecedor são propagadas.

liberarRochaDoFarol() consulta a velocidade e solicita fogo sobre um identificador de rocha. Retorna dados locais do ensaio. Não transporta pessoas, não movimenta o contrapeso, não modela cabos, massa, forças ou dano térmico e não confirma que um farol físico foi liberado. A narrativa contém o resgate e o pacto; o código demonstra a tradução do contrato disponível. rochaLiberada é o resultado declarado pelo simulador, sem sensores ou comprovação física.

Velocidade negativa ou não finita é inválida; zero é aceito como valor numérico e não prova capacidade de transporte. Entradas são tipadas; o programa não valida JSON arbitrário nem decide se qualquer objeto nomeado é uma rocha. private nos parâmetros de construtor é checagem TypeScript, não barreira de segurança em execução.

Números, teste e alternativa

O caso 36 km/h → 10 m/s permite igualdade numérica no exemplo executado. Casos fracionários são testados com tolerância absoluta 1e-12 m/s nos valores pequenos usados. A solução converte nós pelo fator 1852 / 3600 e só arredonda a apresentação com toFixed(3). Não se afirma que todos os números flutuantes tenham equivalência decimal exata, nem se escolhe tolerância para medições reais.

Adapter acrescenta uma camada e regras de tradução que precisam acompanhar os contratos. Se você controla as duas APIs e pode mudar uma delas de modo compatível com seus consumidores, uma alteração direta pode eliminar a necessidade da camada. Uma função que devolve um objeto com velocidadeMps e atacar também pode ser um adaptador; a classe aqui explicita composição e papéis. Os testes usam fornecedores substitutos para observar dados e delegações sem modificar o legado.

Facade oferece entrada conveniente para subsistemas; Adapter atende a um contrato já esperado por um cliente. Bridge separa dimensões de variação planejadas para evoluir; Adapter reconcilia interfaces existentes. A presença de composição ou de uma classe chamada ponte não define essas intenções por si.

Referência e rastreabilidade

O fator do exercício é conferido no NIST Guide to the SI — unidades fora do SI: um nó corresponde a uma milha náutica por hora, com 1852 / 3600 m/s. Consulta em 22/10/2026. A conversão é verificada também pela execução dos testes no runtime fixado.

Saídas e hashes vinculam a execução às fontes. Não representam auditoria técnica independente, aprovação do autor, benchmark ou garantia de integração com uma biblioteca externa real.

02 · Leia o mecanismo

O feitiço, linha por linha.

Comece por src/main.ts para ver o programa em uso. Explore os contratos, a implementação e os testes no seletor de arquivos.

src/main.tsTypeScript
import { DragaoAdapter } from "./adapter.js";
import { liberarRochaDoFarol } from "./cliente.js";
import { DragaoAntigo } from "./legado/dragao-antigo.js";
import { DragaoNativo } from "./nativo.js";

for (const [nome, dragao] of [
  ["Nativo", new DragaoNativo()],
  ["Adaptado", new DragaoAdapter(new DragaoAntigo())],
] as const) {
  const ensaio = liberarRochaDoFarol(dragao, "Trava do farol");
  console.log(`${nome}: ${ensaio.velocidadeMps.toFixed(3)} m/s | ${ensaio.resultado.alvo} | liberada ${ensaio.resultado.rochaLiberada}`);
}

try {
  new DragaoAdapter(new DragaoAntigo()).atacar({ alvo: "Trava do farol", efeito: "gelo" });
} catch (erro: unknown) {
  if (!(erro instanceof Error)) throw erro;
  console.log(`Ordem recusada: ${erro.message}`);
}
A execução do programa é feita localmente.

03 · Revele as conexões

A estrutura por trás da magia.

Veja os papéis e suas relações. Amplie cada vista para ler atributos, métodos e conexões com calma.

DragaoNativo e DragaoAdapter realizam a interface DragaoNovo.
06 · a target

DragaoNovo oferece velocidadeMps(): number e atacar(pedido: PedidoDeAtaque): ResultadoDeAtaque. DragaoNativo atende ao contrato diretamente e conserva metrosPorSegundo como campo privado somente de leitura. DragaoAdapter atende ao mesmo contrato; seus membros selecionados aparecem na vista de adaptação ao legado. A relação de realização usa linha tracejada e triângulo vazio. Membros exibidos são um recorte; construtores e demais membros podem estar omitidos. DragaoNovo: liberarRochaDoFarol recebe este contrato e solicita fogo. Efeito indisponível lança RecursoSemEquivalente.

DragaoAdapter mantém referência a DragaoAntigo por associação direcionada.
06 · b adaptee

DragaoAdapter guarda antigo: DragaoAntigo como referência privada somente de leitura. A seta é associação direcionada; não declara ownership ou composição UML. velocidadeMps divide o valor em km/h por 3,6. atacar traduz o pedido e o objeto devolvido por soltarFogo(alvo: string), com rocha: string e desobstruida: boolean. O legado é uma biblioteca simulada e permanece inalterado. Membros exibidos são um recorte; construtores e demais membros podem estar omitidos. DragaoAdapter: Divide km/h por 3.6; traduz desobstruida para rochaLiberada. DragaoAntigo: Biblioteca simulada: km/h e fogo. Adapter não altera o legado. e3 · referência

DragaoNovo depende de PedidoDeAtaque e ResultadoDeAtaque, com atributos tipados.
06 · c dados

PedidoDeAtaque declara alvo: string e efeito: "fogo" | "gelo". ResultadoDeAtaque conserva esses campos e acrescenta rochaLiberada: boolean. Os atributos dos dois contratos são somente de leitura. As setas tracejadas são dependências da interface DragaoNovo; o booleano é o resultado declarado pelo simulador, sem comprovação física. Membros exibidos são um recorte; construtores e demais membros podem estar omitidos.

04 · Faça sua escolha

Sua vez de conjurar.

exercise/README.md

Exercício — O fornecedor marítimo

Integre um segundo fornecedor que informa velocidade em nós e expõe aquecerRocha(identificador) em vez de soltarFogo(alvo). Ele também oferece somente fogo.

Critérios verificáveis:

  • Um novo adaptador por composição atende DragaoNovo; liberarRochaDoFarol() não muda.
  • 10 nós produzem aproximadamente 5.144444444444444 m/s; compare com tolerância, não como igualdade decimal exata geral.
  • O fator usado é 1852 / 3600, sem arredondamento antecipado.
  • O alvo chega ao fornecedor normalizado e a indicação de liberação é preservada, inclusive quando for false.
  • Pedido de gelo é recusado antes de acionar o fornecedor.
  • Velocidade não finita é diagnosticada.
  • Nenhuma edição é necessária na biblioteca antiga ou no fornecedor marítimo.

Compare com solution/fornecedor-maritimo.ts, solution/adapter-maritimo.ts e solution/maritimo.test.ts. Execute npm run solution. exercise/ fica fora do build oficial para não compilar a tentativa junto da resposta.

Resposta comentada

O adaptador converte os dados e a chamada, não apenas os nomes: nós viram m/s, identificador vira alvo e liberada vira rochaLiberada. O erro do efeito sem equivalente mantém o limite do pacto. O cliente não precisa saber de qual fornecedor veio o resultado.

O programa formata a velocidade com três casas decimais só na saída humana. O teste mantém o resultado numérico e usa tolerância absoluta de 1e-12 m/s para esse caso pequeno. Isso não declara uma tolerância física universal nem valida velocidade de um animal real.

Se ambos os contratos forem controlados pela mesma equipe, alterar a API diretamente pode ser mais claro que manter duas superfícies e um adaptador. Uma função ou um objeto literal também poderia cumprir DragaoNovo; uma classe não é exigência do mecanismo de adaptação por composição.

Compare depois da sua tentativa.

A resposta e seus testes estão na pasta solution/. O sucesso dos testes fornecidos confirma essa resposta; sua tentativa precisa estar incluída na compilação para ser avaliada.

Do estudo à prática

Experimente localmente.

Node 26.10.0 · npm 11.19.1 · TypeScript 5.9.3

Execute os comandos dentro da pasta deste projeto. O lock instala o compilador local. Os programas não são executados no navegador.

cd book-23/code/06-adapter
npm ci --ignore-scripts --no-audit --no-fund
npm test
npm start

# Depois da sua tentativa
npm run solution
Baixar este projeto completo

Diagrama ampliado