Pular para o conteúdo

Padrões Estruturais

Enquanto os criacionais lidam com o nascimento dos objetos e os comportamentais com sua conversa, os estruturais lidam com a montagem: como conectar interfaces incompatíveis, envelopar objetos para adicionar responsabilidades, ou organizar hierarquias. A maioria favorece composição sobre herança, um dos princípios fundacionais do catálogo.

Intenção: converte a interface de uma classe na interface que o cliente espera, permitindo que classes com interfaces incompatíveis trabalhem juntas. Existe em duas formas: adapter de classe (por herança múltipla, limitado em Java) e adapter de objeto (por composição, o mais usado).

Quando usar: integrar uma biblioteca de terceiros ou código legado cuja interface não bate com a esperada pelo seu domínio.

Intenção: desacopla uma abstração de sua implementação para que as duas variem independentemente. Em vez de uma hierarquia combinatória (FormaVermelhaCirculo, FormaAzulQuadrado…), separa “Forma” de “Renderizador” e as compõe.

Quando usar: quando você tem duas dimensões ortogonais de variação que, por herança, gerariam uma explosão de subclasses.

Intenção: compõe objetos em estruturas de árvore para representar hierarquias parte-todo, permitindo que o cliente trate objetos individuais (folhas) e composições (nós) de forma uniforme.

Quando usar: hierarquias recursivas — árvore de arquivos, componentes de UI, expressões, itens de menu.

Intenção: adiciona responsabilidades a um objeto dinamicamente, envelopando-o em outro objeto que implementa a mesma interface. Alternativa flexível à herança para estender comportamento.

Quando usar: quando você quer combinar responsabilidades opcionais em tempo de execução (o clássico BufferedInputStream(new FileInputStream(...)) do java.io).

Intenção: fornece uma interface unificada e de mais alto nível para um conjunto de interfaces de um subsistema, tornando-o mais fácil de usar.

Quando usar: reduzir a superfície de acoplamento entre clientes e um subsistema complexo. Detalhes e contraste com Ports na nota Facade.

Intenção: usa compartilhamento para suportar eficientemente um grande número de objetos de granularidade fina, separando estado intrínseco (compartilhável, imutável) de extrínseco (passado pelo cliente).

Quando usar: milhões de objetos quase iguais (glifos em um editor, partículas, tiles de um mapa) onde a memória é o gargalo.

Intenção: fornece um substituto ou representante de outro objeto para controlar o acesso a ele.

Quando usar: adicionar controle de acesso, lazy loading, cache ou representação remota sem mudar o objeto real. Tipos (virtual, remoto, proteção) e comparação com Decorator na nota Proxy.

IMPORTANTE: Adapter do GoF vs. adapter da Arquitetura Hexagonal

Seção intitulada “IMPORTANTE: Adapter do GoF vs. adapter da Arquitetura Hexagonal”

Os dois conceitos compartilham a ideia de tradução entre interfaces, mas não são idênticos — e confundi-los gera bugs de vocabulário em discussões de design.

Aspecto Adapter (GoF) Adapter Hexagonal (Adapters)
Escopo Micro-padrão de design OO: uma classe traduz a interface de outra Elemento arquitetural: liga a aplicação ao mundo externo através de um Port
Motivação Reaproveitar uma classe com interface incompatível Isolar o núcleo de tecnologia (DB, HTTP, fila) — regra de dependência
Direção Cliente → interface esperada → objeto adaptado Driving (entrada) ou driven (saída), sempre implementando/consumindo um Port
Granularidade Uma classe Um conjunto de classes de infraestrutura

Em outras palavras: todo adapter hexagonal frequentemente usa o padrão Adapter do GoF por dentro (traduzindo, digamos, uma entidade de domínio para um DTO de um driver JDBC), mas o conceito arquitetural é maior — ele existe para satisfazer a regra de dependência da Arquitetura Hexagonal, não apenas para casar duas assinaturas de método. Um é tática; o outro é estratégia. Ver Adapters e Ports.

classDiagram
    class Cliente
    class Alvo {
        <<interface>>
        +requisicao()
    }
    class Adaptado {
        +requisicaoEspecifica()
    }
    class Adapter {
        -adaptado : Adaptado
        +requisicao()
    }
    Cliente --> Alvo : depende
    Alvo <|.. Adapter
    Adapter --> Adaptado : delega
  • Confundir Decorator com Proxy: ambos envelopam e mantêm a mesma interface, mas a intenção difere — Decorator acrescenta comportamento; Proxy controla acesso. Ver Proxy.
  • Facade que vira God Object: uma fachada que acumula lógica de negócio em vez de apenas delegar/coordenar deixa de simplificar e vira um monólito.
  • Composite forçando operações sem sentido na folha: expor adicionar(filho) na interface comum obriga folhas a lançarem exceção, tensionando o LSP.
  • Chamar “adapter hexagonal” de “Adapter do GoF” (e vice-versa): como acima, são conceitos de escopos diferentes; misturá-los confunde discussões arquiteturais.

1. Qual é o foco dos padrões estruturais, em contraste com criacionais e comportamentais?

Resposta

A composição de classes e objetos em estruturas maiores — o encaixe entre partes. Criacionais focam na instanciação; comportamentais, na distribuição de responsabilidade e no fluxo de controle.

2. Como o Adapter do GoF difere do adapter da Arquitetura Hexagonal?

Resposta

O Adapter do GoF é um micro-padrão OO: uma classe traduz a interface de outra. O adapter hexagonal é um elemento arquitetural que liga o núcleo ao exterior implementando/consumindo um Port para satisfazer a regra de dependência. O hexagonal costuma usar o padrão GoF por dentro, mas seu propósito é estratégico, não apenas casar assinaturas.

3. Decorator e Proxy têm a mesma forma; o que os distingue?

Resposta

A intenção. Decorator envelopa para adicionar responsabilidades/comportamento; Proxy envelopa para controlar o acesso ao objeto real (lazy, cache, proteção, remoto). A estrutura é quase idêntica; a diferença está no propósito.

4. Quando o Bridge evita uma explosão de subclasses?

Resposta

Quando há duas dimensões ortogonais de variação (ex: tipo de forma × tipo de renderização). Herança combinaria as duas em N×M subclasses; o Bridge separa abstração de implementação e as compõe, resultando em N+M classes.