← Blog

Design patterns: o catálogo não substitui o problema

O livro de padrões é um vocabulário, não um cardápio. Time que começa pelo Factory, pelo Singleton, pelo Strategy, costuma desenhar a solução antes de ter o problema. O código fica “igual ao diagrama” e o negócio continua difícil de mudar.

Padrão de projeto é uma solução nomeada para um problema que se repete. A ordem importa: primeiro a dor, depois o nome. Se você não consegue dizer a dor em uma frase, ainda não precisa do carimbo.

O que o catálogo realmente oferece

Oferece linguagem compartilhada. Dizer “aqui é um Observer” em uma revisão é mais curto do que descrever lista de inscritos, notificação e ciclo de vida. Oferece um mapa de consequências: o que o padrão deixa fácil e o que deixa chato. Oferece, sobretudo, compressão de experiência alheia — gente que já se queimou no mesmo eixo.

Não oferece qualidade automática. Strategy mal extraído é if disfarçado de classe. Singleton vira variável global com cerimônia. Facade esconde um módulo que deveria ser simples, não um sistema que deveria ser fatiado. O nome sem o problema é jargão.

O catálogo clássico (GoF) nasceu em C++ e Smalltalk, com um conjunto de pressões da época. Em PHP, Python ou Java modernos, algumas pressões mudaram: função de primeira classe reduz Strategy; container de injeção reduz um tipo de Factory; módulo e pacote reduzem Facade. O problema de “variar um algoritmo sem editar o cliente” não mudou. A implementação mínima, sim.

Comece pela dor, não pelo índice

Três dores cobrem boa parte do que o time chama de “precisamos de um pattern”:

Duplicação que diverge. O mesmo fluxo de pagamento copiado em três controladores. Amanhã a regra muda em dois. Extração honesta — função, classe, módulo — vem antes de qualquer nome. Se depois a extração pede variação por tipo, aí o nome pode ser Strategy ou um mapa de handlers.

Eixo de mudança concentrado no lugar errado. Cada novo formato de exportação edita o serviço central. Cada novo meio de notificação abre o Pedido. O núcleo não deveria conhecer os tipos. Separar o que varia — e só o que já variou duas vezes — é o padrão. Template Method, Strategy, Observer, Adapter: todos respondem a um eixo. Sem eixo, são arquivos.

Dependência rígida de um detalhe. O caso de uso instancia o SDK do gateway. O teste precisa de rede. O segundo gateway obriga a reescrever o caso de uso. Aqui nasce Adapter ou uma porta (e o DIP do SOLID). O nome é secundário. A direção da dependência é o desenho.

flowchart TD
  A[Código dói] --> B{Qual a frase da dor?}
  B -->|Não sei| C[Observar mais]
  B -->|Cópia que diverge| D[Extrair]
  B -->|Tipo novo edita o núcleo| E[Separar o que varia]
  B -->|Detalhe no domínio| F[Inverter dependência]
  D --> G{Já precisa de nome?}
  E --> G
  F --> G
  G -->|Sim, o time ganha vocabulário| H[Batizar o padrão]
  G -->|Não| I[Deixar extraído e claro]
  classDef ouro fill:#FBF5E4,stroke:#C9A227,color:#0B1F18,stroke-width:1.4px
  classDef verde fill:#F3FAF7,stroke:#1E7A57,color:#0B1F18,stroke-width:1.4px
  classDef fim fill:#14513B,stroke:#0F3328,color:#FBFAF6,stroke-width:1.4px
  class A,B ouro
  class C,D,E,F,G verde
  class H,I fim

Três padrões, três situações, três abusos

Strategy. Ajuda quando há famílias de algoritmo e o cliente escolhe em runtime: cálculo de frete, pontuação, taxa. O cliente depende da abstração; cada regra nova é uma classe ou uma função. Abuso: uma única implementação “para ficar extensível” e um if dentro do método “por enquanto”.

Observer. Ajuda quando vários interessados reagem a um evento sem o sujeito conhecê-los: “pedido pago” dispara estoque, e-mail, analytics. Acoplamento diminui. Abuso: event bus interno para duas chamadas na mesma transação, ordem indefinida, debug impossível. Às vezes uma chamada explícita é o desenho adulto.

Adapter. Ajuda quando a interface que você tem não é a que o núcleo quer: SDK de pagamento, API antiga, lib de PDF. O domínio fala a porta; o adapter traduz. Abuso: wrapper 1:1 de cada método da lib, sem ganho de teste nem de troca. Tradução sem tensão é burocracia.

Singleton merece menção porque é o mais ensinado e o mais danoso. Ajuda em recurso realmente único e caro, com ciclo de vida claro — e mesmo aí, um container costuma bastar. Abuso: estado global, teste na loteria, ordem de inicialização. “Só pode haver um” raramente é requisito de negócio. Quase sempre é preguiça de passar dependência.

Dor Nome possível Sinal de abuso
Algoritmo varia, cliente estável Strategy Uma classe só, “para o futuro”
Vários ouvintes, sujeito não deve conhecê-los Observer Grafo de eventos para duas funções
Interface externa incompatível Adapter Wrapper sem tensão de troca ou teste
Construção complexa passo a passo Builder Builder para três campos obrigatórios
Recurso único de verdade (quase nunca Singleton) Estado global disfarçado

Padrão na revisão, sem vaidade

O comentário útil não é “faltou um Decorator”. É “este eixo já mudou duas vezes neste arquivo”. Se o autor extraíu e o time reconhece o desenho, batizar ajuda o próximo leitor. Se o autor copiou o diagrama e o eixo não existe, o nome é ruído.

Desenhe o problema no quadro: quem muda, com que frequência, quem não deveria saber. Só então abra o catálogo. Muitas vezes a solução cabe em uma função e um mapa. O fato de não ter nome famoso não a torna amadora.

Quem estuda orientação a objetos na Programming One encontra padrões como vocabulário de problemas recorrentes, não como coleção de classes para espalhar no repositório. Essa ordem — problema, extração, nome — é o que separa desenho de fantasia.

Um exercício de meia hora

  1. Escolha um arquivo com switch ou if por tipo.
  2. Escreva a frase da dor: “cada X novo me obriga a editar Y”.
  3. Extraia o mínimo que isola X.
  4. Só se o time precisar falar sobre isso, dê o nome do catálogo.
  5. Apague qualquer interface que tenha uma implementação e nenhum teste.

O catálogo continua valioso. Ele só não substitui o problema. Sem a dor, o padrão é fantasia de arquitetura. Com a dor, é atalho para uma solução que o time já deveria conhecer pelo nome.

Leia também: SOLID sem dogma e Clean Code: nomes, funções e o custo da pressa.

#Design Patterns#OOP#Arquitetura#Código

Thiago Nogueira

Autor de A Caixa Mágica e das séries Programming One e AI One na Editora Pensar Bem.

Capa de Python One

Python One

Do primeiro print à API REST em produção.