Especialização em Sistemas com Java 21 LTS • Capítulo 05


🎯 Visão Geral dos Exemplos Práticos

Neste laboratório prático, implementaremos exemplos corporativos completos explorando:

  1. Modelagem de Domínio com Encapsulamento Estrito: aplicação de invariantes de saldo, limites de crédito e validações nos setters.
  2. Sobrecarga de Construtores com this(...): encadeamento limpo de inicialização eliminando código duplicado.
  3. Padrão Static Factory Method: criação de instâncias com nomes semânticos e regras pré-definidas para contas PJ e Estudantis.

💻 Exemplo 01 — Sistema Bancário de Alta Integridade

package com.empresa.dominio;

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Objects;

/**
 * Entidade de Conta Bancária Corporativa com validação robusta de regras financeiras.
 */
class ContaBancaria {

    private final String numeroConta;
    private final String agencia;
    private String titular;
    private BigDecimal saldo;
    private BigDecimal limiteChequeEspecial;
    private boolean bloqueada;

    // Construtor Mestre / Canônico
    public ContaBancaria(String numeroConta, String agencia, String titular, 
                         BigDecimal saldoInicial, BigDecimal limiteChequeEspecial) {
        this.numeroConta = Objects.requireNonNull(numeroConta, "Número da conta é obrigatório.");
        this.agencia = Objects.requireNonNull(agencia, "Agência é obrigatória.");
        setTitular(titular);
        this.saldo = (saldoInicial != null) ? saldoInicial : BigDecimal.ZERO;
        this.limiteChequeEspecial = (limiteChequeEspecial != null) ? limiteChequeEspecial : BigDecimal.ZERO;
        this.bloqueada = false;
    }

    // Sobrecarga: Construtor simplificado para novas contas correntes
    public ContaBancaria(String numeroConta, String agencia, String titular) {
        this(numeroConta, agencia, titular, BigDecimal.ZERO, BigDecimal.ZERO);
    }

    // Static Factory Method para Conta Universitária (Isenta com limite fixo de R$ 500)
    public static ContaBancaria criarContaUniversitaria(String numeroConta, String agencia, String estudante) {
        return new ContaBancaria(numeroConta, agencia, estudante, BigDecimal.ZERO, new BigDecimal("500.00"));
    }

    // Static Factory Method para Conta Corporativa (PJ com limite de R$ 50.000)
    public static ContaBancaria criarContaCorporativa(String numeroConta, String agencia, String empresa) {
        return new ContaBancaria(numeroConta, agencia, empresa, new BigDecimal("10000.00"), new BigDecimal("50000.00"));
    }

    public void depositar(BigDecimal valor) {
        if (bloqueada) throw new IllegalStateException("Conta bloqueada para depósitos.");
        if (valor == null || valor.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Valor de depósito inválido: " + valor);
        }
        this.saldo = this.saldo.add(valor);
        System.out.printf("   [DEPÓSITO] +%s creditado na conta %s (Novo Saldo: %s)%n",
                formatarMoeda(valor), numeroConta, formatarMoeda(saldo));
    }

    public boolean sacar(BigDecimal valor) {
        if (bloqueada) throw new IllegalStateException("Conta bloqueada para saques.");
        if (valor == null || valor.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException("Valor de saque inválido: " + valor);
        }

        BigDecimal disponivel = this.saldo.add(this.limiteChequeEspecial);
        if (valor.compareTo(disponivel) > 0) {
            System.out.printf("   [RECUSADO] Tentativa de saque de %s excede saldo + limite (%s)%n",
                    formatarMoeda(valor), formatarMoeda(disponivel));
            return false;
        }

        this.saldo = this.saldo.subtract(valor);
        System.out.printf("   [SAQUE] -%s debitado da conta %s (Saldo Restante: %s)%n",
                formatarMoeda(valor), numeroConta, formatarMoeda(saldo));
        return true;
    }

    public void setTitular(String titular) {
        if (titular == null || titular.trim().length() < 3) {
            throw new IllegalArgumentException("Nome do titular deve ter ao menos 3 caracteres.");
        }
        this.titular = titular.trim();
    }

    private static String formatarMoeda(BigDecimal valor) {
        NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.of("pt", "BR"));
        return nf.format(valor);
    }

    public String getNumeroConta() { return numeroConta; }
    public String getAgencia() { return agencia; }
    public String getTitular() { return titular; }
    public BigDecimal getSaldo() { return saldo; }
    public BigDecimal getLimiteChequeEspecial() { return limiteChequeEspecial; }
    public boolean isBloqueada() { return bloqueada; }
    public void setBloqueada(boolean bloqueada) { this.bloqueada = bloqueada; }
}

public class SistemaOperacoesBancarias {

    public static void main(String[] args) {
        System.out.println("================================================================================");
        System.out.println("             SISTEMA BANCÁRIO CORPORATIVO: MODELAGEM DE DOMÍNIO                 ");
        System.out.println("================================================================================");

        // 1. Abertura via Factory Methods
        ContaBancaria contaEstudante = ContaBancaria.criarContaUniversitaria("10982-1", "0042", "Lucas Gabriel");
        ContaBancaria contaPJ = ContaBancaria.criarContaCorporativa("55432-9", "0042", "Tech Innovations LTDA");

        System.out.printf("Conta 1: %s (Ag: %s) | Titular: %s | Limite: R$ %.2f%n",
                contaEstudante.getNumeroConta(), contaEstudante.getAgencia(),
                contaEstudante.getTitular(), contaEstudante.getLimiteChequeEspecial());

        System.out.printf("Conta 2: %s (Ag: %s) | Titular: %s | Saldo Inicial: R$ %.2f%n%n",
                contaPJ.getNumeroConta(), contaPJ.getAgencia(),
                contaPJ.getTitular(), contaPJ.getSaldo());

        // 2. Operações na conta de estudante
        System.out.println("--- Teste de Operações: Conta Universitária ---");
        contaEstudante.depositar(new BigDecimal("150.00"));
        contaEstudante.sacar(new BigDecimal("300.00")); // Usa limite especial
        contaEstudante.sacar(new BigDecimal("500.00")); // Deve falhar (estoura o limite)

        // 3. Operações na conta PJ e bloqueio de segurança
        System.out.println("\n--- Teste de Bloqueio de Segurança: Conta PJ ---");
        contaPJ.sacar(new BigDecimal("25000.00")); // Saldo vai para negativo (-15000), dentro do limite de 50000
        contaPJ.setBloqueada(true);
        System.out.println("🚨 Conta PJ bloqueada por auditoria!");

        try {
            contaPJ.sacar(new BigDecimal("100.00"));
        } catch (IllegalStateException e) {
            System.out.println("✅ Proteção acionada: " + e.getMessage());
        }
        System.out.println("================================================================================");
    }
}

📋 Resultado Esperado no Console

================================================================================
             SISTEMA BANCÁRIO CORPORATIVO: MODELAGEM DE DOMÍNIO                 
================================================================================
Conta 1: 10982-1 (Ag: 0042) | Titular: Lucas Gabriel | Limite: R$ 500.00
Conta 2: 55432-9 (Ag: 0042) | Titular: Tech Innovations LTDA | Saldo Inicial: R$ 10000.00

--- Teste de Operações: Conta Universitária ---
   [DEPÓSITO] +R$ 150,00 creditado na conta 10982-1 (Novo Saldo: R$ 150,00)
   [SAQUE] -R$ 300,00 debitado da conta 10982-1 (Saldo Restante: -R$ 150,00)
   [RECUSADO] Tentativa de saque de R$ 500,00 excede saldo + limite (R$ 350,00)

--- Teste de Bloqueio de Segurança: Conta PJ ---
   [SAQUE] -R$ 25.000,00 debitado da conta 55432-9 (Saldo Restante: -R$ 15.000,00)
🚨 Conta PJ bloqueada por auditoria!
✅ Proteção acionada: Conta bloqueada para saques.
================================================================================