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:

  1. Substituição Trivial de Provedores: É possível alternar entre GatewayStripe, GatewayCielo ou GatewayMercadoPago alterando unicamente a injeção na inicialização da aplicação, sem alterar uma única linha do CheckoutService.
  2. 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("================================================================================");
    }
}