Sistema bancario
Parte de la sección Programación Orientada a Objetos del Journey de Java de Coddy — lección 85 de 87.
Este desafío te propone construir un Sistema Bancario que modele operaciones financieras del mundo real utilizando principios de POO.
Su sistema debe manejar diferentes tipos de cuenta como SavingsAccount y CheckingAccount, ambos extendiendo una clase base Account. Cada tipo de cuenta tiene comportamientos únicos: las cuentas de ahorro podrían generar intereses, mientras que las cuentas corrientes podrían tener protección contra sobregiros.
Piense en cómo modelar las transacciones. Una interfaz como Transactable podría definir métodos para deposit() y withdraw(). Considere el uso de excepciones personalizadas como InsufficientFundsException para manejar operaciones no válidas de manera elegante.
Una clase Bank podría gestionar múltiples cuentas y clientes, demostrando composición. Podrías aplicar el patrón Factory para crear diferentes tipos de cuentas, o usar el patrón Observer para notificar a los clientes sobre cambios en las cuentas.
Enfócate en el encapsulamiento para proteger datos sensibles como saldos y números de cuenta, y utiliza el polimorfismo para procesar diferentes tipos de cuenta de manera uniforme.
Desafío
Fácil¡Vamos a construir un Sistema Bancario completo que demuestre tu dominio de los principios de la POO! Crearás un sistema con diferentes tipos de cuentas, manejo de transacciones y una gestión adecuada de excepciones, todo organizado en múltiples archivos.
Organizarás tu código en siete archivos:
Transactable.java: Crea una interfaz que defina el contrato para las operaciones financieras. Debe declarar los métodosdeposit(double amount)ywithdraw(double amount), ambos devolviendo un booleano para indicar el éxito.InsufficientFundsException.java: Crea una excepción personalizada que extienda deException. El constructor debe aceptar el monto del retiro intentado y el saldo actual, creando un mensaje con el formato"Insufficient funds: attempted %.2f, available %.2f".Account.java: Crea una clase base abstracta que represente cualquier cuenta bancaria. Incluye campos privados paraaccountNumber(String) ybalance(double), un constructor que inicialice ambos, los getters apropiados, un setter protegido para balance (para que las subclases puedan modificarlo) y un método abstractogetAccountType()que devuelva un String. Implementa un métodogetDetails()que devuelva"%s (%s): $%.2f"con el saldo formateado a 2 decimales.SavingsAccount.java: Crea una clase que extienda deAccounte implementeTransactable. Añade un campo privado parainterestRate(double). El constructor recibe accountNumber, saldo inicial e interestRate. ImplementagetAccountType()para que devuelva"Savings". Paradeposit(), añade el monto al saldo y devuelve true. Parawithdraw(), si el monto excede el saldo, devuelve false; de lo contrario, réstalo y devuelve true. Añade un métodoapplyInterest()que aumente el saldo según el porcentaje de la tasa de interés.CheckingAccount.java: Crea una clase que extienda deAccounte implementeTransactable. Añade un campo privado paraoverdraftLimit(double). El constructor recibe accountNumber, saldo inicial y overdraftLimit. ImplementagetAccountType()para que devuelva"Checking". Paradeposit(), añade el monto y devuelve true. Parawithdraw(), permite el retiro si el monto es menor o igual al saldo más el overdraftLimit; devuelve false si excede este límite.Bank.java: Crea una clase que gestione las cuentas usando un ArrayList. Incluye los métodos:addAccount(Account account)- añade una cuenta al bancofindAccount(String accountNumber)- devuelve la Account o null si no se encuentratransfer(String fromAccount, String toAccount, double amount)- transfiere dinero entre cuentas, lanzandoInsufficientFundsExceptionsi la cuenta de origen no tiene fondos suficientes. En caso de éxito, devuelve"Transferred $%.2f from %s to %s"getTotalDeposits()- devuelve la suma de todos los saldos de las cuentas
Main.java: ¡Construye tu sistema bancario! Recibirás una cadena de comandos separados por comas:"SAVINGS:accountNumber:balance:interestRate""CHECKING:accountNumber:balance:overdraftLimit""DEPOSIT:accountNumber:amount""WITHDRAW:accountNumber:amount""TRANSFER:fromAccount:toAccount:amount""INTEREST:accountNumber"
Procesa cada comando e imprime:
- SAVINGS/CHECKING:
"Account created: " + accountNumber - DEPOSIT:
"Deposited $%.2f to %s%n" - WITHDRAW:
"Withdrew $%.2f from %s%n"en caso de éxito, o"Withdrawal failed: " + accountNumber - TRANSFER: Imprime el mensaje de éxito o
"Transfer failed: " + e.getMessage() - INTEREST:
"Interest applied to " + accountNumber
Después de todos los comandos, imprime
"--- Bank Summary ---"seguido de los detalles de cada cuenta (usandogetDetails()) y finalmente"Total deposits: $%.2f%n"formateado a 2 decimales.
Recibirás una entrada: la cadena de comandos separados por comas.
Por ejemplo, con la 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, tu salida sería:
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¡Observa cómo la cuenta corriente permite el retiro de $600 a pesar de tener solo $500 de saldo; esa es la protección contra sobregiros en acción! La cuenta de ahorros gana un 5% de interés sobre su saldo después de la transferencia. ¡Este desafío combina herencia, interfaces, polimorfismo, excepciones personalizadas y encapsulamiento en una aplicación bancaria realista!
Hoja de referencia
Un Sistema Bancario demuestra los principios de la POO a través de la gestión de cuentas, transacciones y el manejo de excepciones.
Interfaces para Contratos
Define operaciones comunes utilizando interfaces:
public interface Transactable {
boolean deposit(double amount);
boolean withdraw(double amount);
}Excepciones Personalizadas
Crea excepciones personalizadas para errores específicos del dominio:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(double attempted, double available) {
super("Insufficient funds: attempted " + attempted + ", available " + available);
}
}Clases Base Abstractas
Utiliza clases abstractas para definir una estructura común con métodos abstractos para el comportamiento específico de las subclases:
public abstract class Account {
private String accountNumber;
private double balance;
public abstract String getAccountType();
protected void setBalance(double balance) {
this.balance = balance;
}
}Herencia y Polimorfismo
Las subclases extienden las clases base e implementan interfaces:
public class SavingsAccount extends Account implements Transactable {
private double interestRate;
@Override
public String getAccountType() {
return "Savings";
}
public void applyInterest() {
setBalance(getBalance() * (1 + interestRate));
}
}Composición
Las clases pueden gestionar colecciones de otros objetos:
public class Bank {
private ArrayList<Account> accounts;
public void addAccount(Account account) {
accounts.add(account);
}
public Account findAccount(String accountNumber) {
// Buscar y devolver la cuenta o null
}
}Encapsulación
Protege los datos sensibles con campos privados y acceso controlado a través de getters/setters. Utiliza modificadores protected para permitir el acceso a las subclases manteniendo la encapsulación.
Manejo de Excepciones en Transacciones
Lanza excepciones personalizadas para operaciones no vá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;
}Pruébalo tú mismo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
// TODO: Crear una instancia de Bank
// TODO: Dividir la entrada por comas para obtener comandos individuales
// TODO: Procesar cada comando:
// - SAVINGS:accountNumber:balance:interestRate -> Crear SavingsAccount, imprimir "Account created: [accountNumber]"
// - CHECKING:accountNumber:balance:overdraftLimit -> Crear CheckingAccount, imprimir "Account created: [accountNumber]"
// - DEPOSIT:accountNumber:amount -> Depositar e imprimir "Deposited $[amount] to [accountNumber]"
// - WITHDRAW:accountNumber:amount -> Retirar e imprimir éxito o "Withdrawal failed: [accountNumber]"
// - TRANSFER:fromAccount:toAccount:amount -> Transferir e imprimir éxito o "Transfer failed: [exception message]"
// - INTEREST:accountNumber -> Aplicar intereses e imprimir "Interest applied to [accountNumber]"
// TODO: Después de todos los comandos, imprimir "--- Bank Summary ---"
// TODO: Imprimir los detalles de cada cuenta usando getDetails()
// TODO: Imprimir "Total deposits: $[total]" formateado a 2 decimales
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a la OOPClases vs. ObjetosLa palabra clave thisMétodosCampos (Atributos)Método constructorSobrecarga de constructoresResumen - Calculadora simple4Herencia
Herencia básica (extends)La palabra clave superSobrescritura de métodos (@Override)Encadenamiento de constructoresLa clase ObjectHerencia simple y multinivelPor qué no hay herencia múltiple de clasesResumen - Jerarquía de empleados7Métodos especiales y la clase Object
Método toString()equals() y hashCode()Método clone()compareTo() y ComparableInterfaz ComparatorResumen - Ordenamiento personalizado2Modificadores de acceso y encapsulamiento
Visión general de los niveles de accesoMétodos Getter y SetterOcultamiento de informaciónLa palabra clave finalResumen - Gestor de cuentas bancarias5Polimorfismo
Fundamentos de sobrecarga de métodosSobrescritura de métodos (tiempo de ejecución)Upcasting y DowncastingEl operador instanceofClases y métodos abstractosResumen - Calculadora de figuras8Conceptos avanzados de POO
Composición vs. HerenciaAgregación vs. ComposiciónClases internas, anidadas y anónimasEnums y métodos de EnumRecords (Java 16+)Clases selladas (Java 17+)11Patrones de diseño - Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón BuilderPatrón ObserverPatrón Strategy14Desafíos finales
Plataforma de E-LearningSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículos3Propiedades de clase y miembros estáticos
Variables de instancia vs. estáticasMétodos estáticosBloques estáticosConstantes (static final)Repaso - Contador y utilidad6Interfaces y Clases Abstractas
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesMétodos Default y Static en InterfacesClases Abstractas vs InterfacesInterfaces FuncionalesResumen - Sistema de Pagos9Genéricos
Introducción a los genéricosClases genéricasMétodos genéricosParámetros de tipo delimitadosComodines (?, extends, super)Resumen - Contenedor genérico12Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Iterator