Separated Interface
Definição (Fowler)
Seção intitulada “Definição (Fowler)”“Define an interface in a separate package from its implementation.”
O ponto não é apenas “ter uma interface”. É onde ela mora. A interface fica junto do cliente que a consome; a implementação fica em outro pacote, que depende do primeiro. O sentido da dependência de código-fonte se inverte em relação ao fluxo de execução.
Problema que resolve
Seção intitulada “Problema que resolve”Sem essa separação, o módulo de alto nível precisa importar o de baixo nível para conseguir chamá-lo — e passa a depender de banco, framework ou serviço externo em tempo de compilação. Isso torna a política impossível de compilar, testar ou reusar isoladamente, e qualquer troca de tecnologia obriga a recompilar (e frequentemente reescrever) o núcleo.
Quando usar
Seção intitulada “Quando usar”- Quando o cliente precisa ser independente do fornecedor em tempo de compilação.
- Quando há múltiplas implementações previstas, ou uma delas é volátil (banco, gateway externo, mensageria).
- Quando se deseja testar a política sem a infraestrutura.
- Quando o cliente e o implementador pertencem a times ou módulos de build diferentes.
Onde colocar a interface
Seção intitulada “Onde colocar a interface”Fowler discute duas opções, e a escolha muda o significado do padrão:
- No pacote do cliente — a interface é propriedade de quem a usa; ela expressa o que o cliente precisa. É esta variante que produz a inversão de dependência.
- Num pacote terceiro, separado de ambos — útil quando há vários clientes ou quando o contrato é compartilhado, mas a inversão é mais fraca: ninguém “possui” o contrato em nome da política.
Exemplo Java/Spring
Seção intitulada “Exemplo Java/Spring”Interface no pacote do domínio, no vocabulário do domínio:
package com.exemplo.domain.pedido;
public interface Pedidos { void registrar(Pedido pedido); Optional<Pedido> porId(PedidoId id); List<Pedido> aguardandoPagamento();}Implementação em outro pacote, importando o domínio:
package com.exemplo.infrastructure.persistence;
import com.exemplo.domain.pedido.Pedido;import com.exemplo.domain.pedido.PedidoId;import com.exemplo.domain.pedido.Pedidos;
@Repositorypublic class JdbcPedidos implements Pedidos {
private final JdbcTemplate jdbcTemplate;
public JdbcPedidos(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; }
@Override public void registrar(Pedido pedido) { jdbcTemplate.update("INSERT INTO pedido (id, total) VALUES (?, ?)", pedido.id().valor(), pedido.total()); }
// demais métodos}O pacote domain não contém nenhum import de infrastructure. O teste é mecânico: apague infrastructure e o domínio ainda compila. O caminho inverso não é verdadeiro — e é exatamente essa assimetria que caracteriza o padrão.
Diagrama
Seção intitulada “Diagrama”graph LR
subgraph domain
Svc[ProcessadorPedido]
Port[[interface Pedidos]]
end
subgraph infrastructure
Impl[JdbcPedidos]
end
Svc -->|usa| Port
Impl -.implementa / importa.-> Port
Impl --> DB[(PostgreSQL)]
A seta de execução vai de ProcessadorPedido até o banco; a seta de compilação vai de JdbcPedidos para domain. Sentidos opostos.
Como a implementação chega ao cliente
Seção intitulada “Como a implementação chega ao cliente”Se o cliente não pode importar o pacote da implementação, alguém de fora precisa fornecê-la. Daí a associação frequente com injeção de dependência: um Plugin (outro padrão de Fowler), um container como o Spring, ou uma fábrica configurada no composition root da aplicação — sempre num módulo que pode depender dos dois lados.
Vale a distinção: Separated Interface resolve onde a interface mora; injeção de dependência resolve como a implementação é entregue. São complementares, e usar injeção sem separar os pacotes não produz inversão.
Anti-padrões e erros comuns
Seção intitulada “Anti-padrões e erros comuns”- Interface no pacote da implementação — o erro central: o cliente continua importando o pacote do detalhe, e não há inversão.
- Interface extraída da classe concreta — mesmos métodos, mesmo vocabulário de tecnologia. A dependência sintática inverte, mas a semântica não: qualquer mudança no detalhe ainda força mudança no contrato.
- Uma interface para cada classe — aplicar o padrão a colaboradores internos e estáveis gera cerimônia sem retorno. Separe nas fronteiras que variam.
- Contrato genérico demais — interfaces como
Repositorio<T>com CRUD genérico não expressam necessidade do cliente; voltam a ser vocabulário de persistência.
Relações
Seção intitulada “Relações”- É o mecanismo que realiza o DIP - Dependency Inversion Principle no nível de pacotes.
- Ports na Arquitetura Hexagonal são Separated Interfaces de propriedade do domínio; Adapters são as implementações.
- Sustenta A Regra da Dependência da Clean Architecture.
- Repositórios do Domain-Driven Design são o caso mais comum: interface no domínio, implementação na infraestrutura.
- Aplica-se a Gateway e DAO - Data Access Object quando se quer isolar o cliente do fornecedor.
- Índice: PoEAA.
Perguntas de revisão
Seção intitulada “Perguntas de revisão”1. O que distingue Separated Interface de simplesmente “programar para uma interface”?
Resposta
A localização. O padrão exige que a interface fique num pacote separado da implementação — idealmente no pacote do cliente. Ter uma interface que mora junto da implementação não muda a direção da dependência.
2. Qual teste mecânico confirma que o padrão foi aplicado?
Resposta
Apagar (ou remover do classpath) o módulo da implementação e verificar se o módulo do cliente ainda compila. Se compila, a dependência aponta do detalhe para a política.
3. Por que o padrão costuma vir acompanhado de injeção de dependência?
Resposta
Porque o cliente não pode importar a implementação — logo, não pode instanciá-la. Alguém externo (container, fábrica, composition root) precisa fornecer a instância concreta em tempo de execução.
4. Uma interface com vocabulário de persistência colocada no pacote do domínio satisfaz o padrão?
Resposta
Satisfaz a letra — a dependência de compilação está invertida. Mas o contrato continua descrevendo o detalhe, então mudanças de tecnologia ainda atravessam a fronteira. A separação de pacotes é necessária, não suficiente.