Menu
Coddy logo textTech

Sistema Bancário

Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 85 de 87.

Este desafio propõe a construção de um Sistema Bancário que modela operações financeiras do mundo real usando princípios de POO.

Seu sistema deve lidar com diferentes tipos de conta como SavingsAccount e CheckingAccount, ambos estendendo uma Account class base. Cada tipo de conta possui comportamentos únicos: contas de poupança podem render juros, enquanto contas correntes podem ter proteção contra cheque especial.

Pense em como modelar transações. Uma interface como Transactable poderia definir métodos para deposit() e withdraw(). Considere usar exceções personalizadas, como InsufficientFundsException, para lidar com operações inválidas de forma elegante.

Uma classe Bank pode gerenciar múltiplas contas e clientes, demonstrando composição. Você poderia aplicar o padrão Factory para criar diferentes tipos de conta, ou usar o padrão Observer para notificar os clientes sobre mudanças na conta.

Foque no encapsulamento para proteger dados sensíveis, como saldos e números de conta, e use o polimorfismo para processar diferentes tipos de conta de forma uniforme.

challenge icon

Desafio

Fácil

Vamos construir um Sistema Bancário completo que demonstre seu domínio dos princípios de POO! Você criará um sistema com diferentes tipos de conta, tratamento de transações e gerenciamento adequado de exceções — tudo organizado em vários arquivos.

Você organizará seu código em sete arquivos:

  • Transactable.java: Crie uma interface que defina o contrato para operações financeiras. Ela deve declarar os métodos deposit(double amount) e withdraw(double amount), ambos retornando um booleano para indicar o sucesso.
  • InsufficientFundsException.java: Crie uma exceção personalizada que estenda Exception. O construtor deve aceitar o valor da tentativa de saque e o saldo atual, criando uma mensagem no formato "Insufficient funds: attempted %.2f, available %.2f".
  • Account.java: Crie uma classe base abstrata representando qualquer conta bancária. Inclua campos privados para accountNumber (String) e balance (double), um construtor que inicialize ambos, getters apropriados, um setter protegido para o saldo (para que as subclasses possam modificá-lo) e um método abstrato getAccountType() que retorne uma String. Implemente um método getDetails() que retorne "%s (%s): $%.2f" com o saldo formatado para 2 casas decimais.
  • SavingsAccount.java: Crie uma classe que estenda Account e implemente Transactable. Adicione um campo privado para interestRate (double). O construtor recebe accountNumber, saldo inicial e interestRate. Implemente getAccountType() para retornar "Savings". Para deposit(), adicione o valor ao saldo e retorne true. Para withdraw(), se o valor exceder o saldo, retorne false; caso contrário, subtraia e retorne true. Adicione um método applyInterest() que aumente o saldo pela porcentagem da taxa de juros.
  • CheckingAccount.java: Crie uma classe que estenda Account e implemente Transactable. Adicione um campo privado para overdraftLimit (double). O construtor recebe accountNumber, saldo inicial e overdraftLimit. Implemente getAccountType() para retornar "Checking". Para deposit(), adicione o valor e retorne true. Para withdraw(), permita o saque se o valor for menor ou igual ao saldo mais o overdraftLimit; retorne false se exceder esse limite.
  • Bank.java: Crie uma classe que gerencie contas usando um ArrayList. Inclua os métodos:
    • addAccount(Account account) - adiciona uma conta ao banco
    • findAccount(String accountNumber) - retorna a Account ou null se não for encontrada
    • transfer(String fromAccount, String toAccount, double amount) - transfere dinheiro entre contas, lançando InsufficientFundsException se a conta de origem tiver fundos insuficientes. Em caso de sucesso, retorne "Transferred $%.2f from %s to %s"
    • getTotalDeposits() - retorna a soma de todos os saldos das contas
  • Main.java: Construa seu sistema bancário! Você receberá uma string de comandos separada por vírgulas:
    • "SAVINGS":accountNumber:balance:interestRate
    • "CHECKING":accountNumber:balance:overdraftLimit
    • "DEPOSIT":accountNumber:amount
    • "WITHDRAW":accountNumber:amount
    • "TRANSFER":fromAccount:toAccount:amount
    • "INTEREST":accountNumber

    Processe cada comando e imprima:

    • SAVINGS/CHECKING: "Account created: " seguido pelo accountNumber
    • DEPOSIT: "Deposited $%.2f to %s%n"
    • WITHDRAW: "Withdrew $%.2f from %s%n" em caso de sucesso, ou "Withdrawal failed: " seguido pelo accountNumber
    • TRANSFER: Imprima a mensagem de sucesso ou "Transfer failed: " seguido pela mensagem da exceção
    • INTEREST: "Interest applied to " seguido pelo accountNumber

    Após todos os comandos, imprima "--- Bank Summary ---" seguido pelos detalhes de cada conta (usando getDetails()) e, finalmente, "Total deposits: $%.2f%n" formatado para 2 casas decimais.

Você receberá uma entrada: a string de comandos separada por vírgulas.

Por exemplo, com a entrada SAVINGS:SAV001:1000.00:0.05,CHECKING:CHK001:500.00:200.00,DEPOSIT:SAV001:250.00,WITHDRAW:CHK001:600.00,TRANSFER:SAV001:CHK001:100.00,INTEREST:SAV001, sua saída seria:

Account created: SAV001
Account created: CHK001
Deposited $250.00 to SAV001
Withdrew $600.00 from CHK001
Transferred $100.00 from SAV001 to CHK001
Interest applied to SAV001
--- Bank Summary ---
SAV001 (Savings): $1207.50
CHK001 (Checking): $0.00
Total deposits: $1207.50

Observe como a conta corrente permite o saque de $600, apesar de ter apenas $500 de saldo — essa é a proteção de cheque especial em ação! A conta poupança ganha 5% de juros sobre seu saldo após a transferência. Este desafio combina herança, interfaces, polimorfismo, exceções personalizadas e encapsulamento em uma aplicação bancária realista!

Folha de consulta

Um Sistema Bancário demonstra os princípios de POO através do gerenciamento de contas, transações e tratamento de exceções.

Interfaces para Contratos

Defina operações comuns usando interfaces:

public interface Transactable {
    boolean deposit(double amount);
    boolean withdraw(double amount);
}

Exceções Personalizadas

Crie exceções personalizadas para erros específicos do domínio:

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(double attempted, double available) {
        super("Insufficient funds: attempted " + attempted + ", available " + available);
    }
}

Classes Base Abstratas

Use classes abstratas para definir uma estrutura comum com métodos abstratos para comportamentos específicos de subclasses:

public abstract class Account {
    private String accountNumber;
    private double balance;
    
    public abstract String getAccountType();
    
    protected void setBalance(double balance) {
        this.balance = balance;
    }
}

Herança e Polimorfismo

Subclasses estendem classes base e implementam interfaces:

public class SavingsAccount extends Account implements Transactable {
    private double interestRate;
    
    @Override
    public String getAccountType() {
        return "Savings";
    }
    
    public void applyInterest() {
        setBalance(getBalance() * (1 + interestRate));
    }
}

Composição

Classes podem gerenciar coleções de outros objetos:

public class Bank {
    private ArrayList<Account> accounts;
    
    public void addAccount(Account account) {
        accounts.add(account);
    }
    
    public Account findAccount(String accountNumber) {
        // Pesquisa e retorna a conta ou null
    }
}

Encapsulamento

Proteja dados sensíveis com campos privados e acesso controlado através de getters/setters. Use modificadores protected para permitir o acesso de subclasses enquanto mantém o encapsulamento.

Tratamento de Exceções em Transações

Lance exceções personalizadas para operações inválidas:

public String transfer(String from, String to, double amount) throws InsufficientFundsException {
    if (!fromAccount.withdraw(amount)) {
        throw new InsufficientFundsException(amount, fromAccount.getBalance());
    }
    toAccount.deposit(amount);
    return "Transferred $" + amount;
}

Experimente você mesmo

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Criar uma instância de Bank
        
        // TODO: Dividir a entrada por vírgula para obter comandos individuais
        
        // TODO: Processar cada comando:
        // - SAVINGS:accountNumber:balance:interestRate -> Criar SavingsAccount, imprimir "Account created: [accountNumber]"
        // - CHECKING:accountNumber:balance:overdraftLimit -> Criar CheckingAccount, imprimir "Account created: [accountNumber]"
        // - DEPOSIT:accountNumber:amount -> Depositar e imprimir "Deposited $[amount] to [accountNumber]"
        // - WITHDRAW:accountNumber:amount -> Sacar e imprimir sucesso ou "Withdrawal failed: [accountNumber]"
        // - TRANSFER:fromAccount:toAccount:amount -> Transferir e imprimir sucesso ou "Transfer failed: [exception message]"
        // - INTEREST:accountNumber -> Aplicar juros e imprimir "Interest applied to [accountNumber]"
        
        // TODO: Após todos os comandos, imprimir "--- Bank Summary ---"
        
        // TODO: Imprimir os detalhes de cada conta usando getDetails()
        
        // TODO: Imprimir "Total deposits: $[total]" formatado para 2 casas decimais
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos