Capítulo 10: Interfaces, Contratos, Métodos Default, Métodos Privados e Inversão de Controle
Especialização em Sistemas com Java 21 LTS • Módulo de Herança e Contratos
🗺️ Mapa Conceitual do Tópico
classDiagram
class GatewayPagamento {
<<interface>>
+autorizar(BigDecimal valor)* RespostaAutorizacao
+capturar(String idTransacao)* boolean
+estornar(String idTransacao)* boolean
+processarComRetry(BigDecimal valor, int maxTentativas) RespostaAutorizacao$
-validarPayload(BigDecimal valor)$
}
class GatewayPix {
+autorizar(BigDecimal valor) RespostaAutorizacao
+capturar(String idTransacao) boolean
+estornar(String idTransacao) boolean
}
class GatewayCartaoCredito {
+autorizar(BigDecimal valor) RespostaAutorizacao
+capturar(String idTransacao) boolean
+estornar(String idTransacao) boolean
}
class CheckoutService {
-GatewayPagamento gateway
+CheckoutService(GatewayPagamento gateway)
+finalizarCompra(BigDecimal total) boolean
}
GatewayPagamento <|.. GatewayPix : "implements"
GatewayPagamento <|.. GatewayCartaoCredito : "implements"
CheckoutService o--> GatewayPagamento : "DIP / Injeção de Dependência"
note for GatewayPagamento "Recursos Modernos:
- default methods (Java 8+)
- private methods (Java 9+)
- Múltipla implementação permitida"
🔌 1. Interfaces como Contratos de Arquitetura
No ecossistema Java, uma Interface define um contrato estrito de comportamento. Classes que implementam a interface comprometem-se formalmente a cumprir as assinaturas dos métodos contratados, permitindo desacoplamento total entre quem consome o serviço e quem o implementa.
Princípios Chave de Design:
- Herança Múltipla de Contrato: Enquanto uma classe só pode herdar de uma única superclasse (
extends), ela pode implementar um número ilimitado de interfaces (implements Autenticavel, Serializavel, Notificavel). - Segregação de Interfaces (ISP - SOLID): “Nenhum cliente deve ser forçado a depender de métodos que não utiliza.” É preferível ter cinco interfaces pequenas e especializadas do que uma única interface “inchada” (Fat Interface).
- Inversão de Dependências (DIP - SOLID): Módulos de alto nível não devem depender de módulos de baixo nível; ambos devem depender de abstrações (interfaces).
⚙️ 2. A Evolução das Interfaces no Java Moderno
Historicamente, interfaces só podiam conter assinaturas abstratas e constantes estáticas (public static final). Do Java 8 ao 21, as interfaces tornaram-se extraordinariamente expressivas:
1. Métodos default (Java 8+)
Permitem fornecer uma implementação padrão em um método da interface. Foram criados originalmente para viabilizar a evolução da Collections API (adicionando métodos como .stream() e .forEach()) sem quebrar bilhões de linhas de código em bibliotecas legadas ao redor do mundo.
public interface Repositorio<T> {
void salvar(T entidade);
// Método default herdado por quem não desejar customizá-lo
default void salvarEmLote(List<T> entidades) {
for (T e : entidades) {
salvar(e);
}
}
}
2. O Conflito do Diamante com Métodos Default
Se uma classe implementar duas interfaces distintas que contenham o mesmo método default com idêntica assinatura, o compilador apontará erro de colisão (Diamond Problem). A classe é obrigada a desambiguar explicitamente:
@Override
public void autenticar() {
AutenticadorOAuth.super.autenticar(); // Escolhe a implementação específica
}
3. Métodos Privados (private / private static no Java 9+)
Permitem encapsular blocos de código auxiliares compartilhados entre múltiplos métodos default dentro da própria interface, evitando expor métodos utilitários internos no contrato público:
public interface ValidadorFiscal {
default void validarNota(BigDecimal total) {
checarValorPositivo(total);
// Regras específicas...
}
private void checarValorPositivo(BigDecimal v) {
if (v == null || v.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Valor fiscal deve ser estritamente positivo.");
}
}
}
🎯 3. Inversão de Controle (IoC) e Injeção de Dependências
Ao projetar serviços que recebem instâncias via interface através do construtor (Constructor Injection), obtemos:
- Substituição Trivial de Provedores: É possível alternar entre
GatewayStripe,GatewayCieloouGatewayMercadoPagoalterando unicamente a injeção na inicialização da aplicação, sem alterar uma única linha doCheckoutService. - Testabilidade Absoluta: Em testes unitários com JUnit e Mockito, a dependência externa pode ser substituída por um Mock que responde instantaneamente sem invocar serviços de rede reais.
📊 4. Matriz Comparativa: Interface vs Classe Abstrata
| Propriedade | Interface (interface) |
Classe Abstrata (abstract class) |
|---|---|---|
| Herança Múltipla | Sim (implements A, B, C) |
Não (apenas herança simples extends) |
| Estado de Instância | Não possui (apenas public static final) |
Sim (variáveis mutáveis privadas/protegidas) |
| Construtores | Proibidos (não pode ter construtor) | Permitidos (acionados via super()) |
| Visibilidade dos Métodos | public, default, private |
Qualquer modificador (private, protected, etc.) |
| Finalidade Primária | Definir um contrato de capacidades (can-do) | Compartilhar esqueleto e estado entre subtipos afins |
💻 5. Código de Demonstração Corporativo (Java 21 LTS)
package com.empresa.contratos;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.UUID;
/**
* Contrato de Gateway de Pagamento moderno com métodos default e privados.
*/
public class SistemaPagamentoContratos {
public record TransacaoResultado(String idTransacao, boolean aprovada, String protocolo) {}
public interface GatewayPagamento {
// Métodos abstratos obrigatórios
TransacaoResultado autorizar(BigDecimal valor, String documentoCliente);
boolean estornar(String idTransacao);
// Método default com lógica de retentativa resiliente
default TransacaoResultado autorizarComRetry(BigDecimal valor, String documento, int maxTentativas) {
validarRequisicao(valor, documento); // Chamada a método privado da interface
for (int tentativa = 1; tentativa <= maxTentativas; tentativa++) {
try {
TransacaoResultado resultado = autorizar(valor, documento);
if (resultado.aprovada()) {
return resultado;
}
} catch (Exception e) {
System.out.printf(" [RETRY %d/%d] Falha temporária no gateway: %s%n", tentativa, maxTentativas, e.getMessage());
}
}
return new TransacaoResultado("FALHA-RETRY", false, "EXCEDEU_TENTATIVAS");
}
// Método privado de validação (Java 9+)
private void validarRequisicao(BigDecimal valor, String documento) {
Objects.requireNonNull(valor, "Valor não pode ser nulo.");
Objects.requireNonNull(documento, "Documento não pode ser nulo.");
if (valor.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("Valor deve ser maior que zero.");
}
}
}
public static class GatewayPix implements GatewayPagamento {
@Override
public TransacaoResultado autorizar(BigDecimal valor, String documentoCliente) {
String txId = "PIX-" + UUID.randomUUID().toString().substring(0, 8);
System.out.printf("⚡ [PIX] Gerando QR Code dinâmico para CPF %s no valor de R$ %.2f...%n", documentoCliente, valor);
return new TransacaoResultado(txId, true, "AUTH-PIX-BANCO-CENTRAL");
}
@Override
public boolean estornar(String idTransacao) {
System.out.printf("⚡ [PIX] Devolução via MED processada para a transação %s.%n", idTransacao);
return true;
}
}
// Serviço cliente desacoplado (Depende apenas da interface GatewayPagamento)
public static class CheckoutService {
private final GatewayPagamento gateway;
public CheckoutService(GatewayPagamento gateway) {
this.gateway = gateway;
}
public void processarPedido(BigDecimal total, String cpf) {
System.out.println("Iniciando checkout desacoplado...");
TransacaoResultado res = gateway.autorizarComRetry(total, cpf, 3);
System.out.printf("Resultado do Pagamento: %s (Protocolo: %s)%n",
res.aprovada() ? "APROVADO ✅" : "REPROVADO ❌", res.protocolo());
}
}
public static void main(String[] args) {
System.out.println("================================================================================");
System.out.println(" ARQUITETURA DESACOPLADA COM INTERFACES MODERNAS (JAVA 21) ");
System.out.println("================================================================================");
GatewayPagamento pixGateway = new GatewayPix();
CheckoutService checkout = new CheckoutService(pixGateway);
checkout.processarPedido(new BigDecimal("489.90"), "123.456.789-00");
System.out.println("================================================================================");
}
}