Hoy vamos a resolver un ejercicio de programación en Java usando programación orientada a objetos y lo que conlleva.
Veremos unas clases y clases abstractas que van a servir para llevar el control de gastos personales.
Te aviso desde ahora que solo te enseñaré las clases, pero no su implementación, ya que solo eso es lo que falta: un menú para invocar a los métodos de las clases e imprimir los resultados.
Obviamente tú puedes implementar este menú en consola, en una GUI, en un servidor web, etcétera.
La práctica consiste en crear una aplicación de gestión de gastos personales. A través de un menú interactivo por la consola, introducir ingresos y gastos para así poder llevar un pequeño control de nuestra economía.
Esta clase será la encargada de gestionar un único usuario. Éste se creará al inicio del programa leyendo datos por el teclado. Ejemplo de datos correctos:
El DNI deberá tener un formato concreto, está comprobación la realizará en la función setter, la cual devolverá un booleano conforme es correcto o no. Si el DNI es correcto quedará asignado.
Formato correcto:
Tendrá una función toString
con la que devolver su contenido.
Las clases Gasto
e Ingreso
heredarán de Dinero
(clase abstracta) y tendrán un único constructor en el que se inicializarán los valores recibidos por parámetros.
Además, tendrán una función toString
con la que devolver su contenido.
Clase donde se gestionarán todos los movimientos de dinero tanto ingresos como gastos.
Inicialmente (en el constructor) se recibirá el usuario que es dueño de la cuenta y el saldo inicial será de 0.
Al añadir un nuevo ingreso se sumará al saldo de la cuenta teniendo en esta variable nuestro dinero real, la función devolverá el saldo de la cuenta.
Al añadir un nuevo gasto se debe comprobar si se dispone de saldo suficiente, en caso contrario se deberá lanzar una nueva excepción del tipo GastoException()
, pero el programa no debe finalizar.
Si se dispone de saldo suficiente se restará el importe del gasto y se devolverá el saldo de la cuenta.
Las funciones getGastos
y getIngresos
nos devolverán todos los movimientos de un tipo u otro. Tendrán una función toString
con la que devolverá el usuario y su saldo.
Una vez que hemos visto los requisitos de esta aplicación, veamos el código. Comencemos viendo la clase abstracta Dinero:
abstract class Dinero {
private double dinero;
private String description;
public double getDinero() {
return dinero;
}
public void setDinero(double dinero) {
this.dinero = dinero;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Recuerda que una clase abstracta no se puede instanciar, solo se puede extender desde otras clases. Y hablando de las clases que la extienden tenemos al gasto y al ingreso:
class Gasto extends Dinero {
public Gasto(double gasto, String description) {
this.setDinero(gasto);
this.setDescription(description);
}
@Override
public String toString() {
return this.getDescription() + " " + this.getDinero();
}
}
class Ingreso extends Dinero {
public Ingreso(double ingreso, String description) {
this.setDinero(ingreso);
this.setDescription(description);
}
@Override
public String toString() {
return this.getDescription() + " " + this.getDinero();
}
}
Por otro lado vamos a tener al usuario. Recuerda que se debe validar el DNI así que presta atención al método setDNI:
class Usuario {
private String nombre;
private int edad;
private String DNI;
public Usuario() {
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public String getDNI() {
return DNI;
}
public boolean setDNI(String DNI) {
// Solo puede medir 9 (sin guión) o 10 (con guión)
if (DNI.length() != 9 && DNI.length() != 10) {
return false;
}
// Si mide 10, debe tener un guión en la posición 8
if (DNI.length() == 10) {
// Extraerlo y regresar false si no es un guión
String posibleGuion = String.valueOf(DNI.charAt(8));
if (!posibleGuion.equals("-")) {
return false;
}
}
// Hasta ahora sabemos que mide 9 o 10 y que el guión es válido (esté presente o no)
String primerosOcho = DNI.substring(0, 8);
String ultimo = String.valueOf(DNI.charAt(DNI.length() - 1));
// Comprobar que los primeros 8 sean numéricos
if (!primerosOcho.matches("[0-9]+")) {
return false;
}
// Comprobar que el último sea una letra
if (!ultimo.matches("[A-Z]+")) {
return false;
}
// Si llegamos hasta aquí y no regresamos arriba, entonces el DNI es válido
this.DNI = DNI;
return true;
}
@Override
public String toString() {
return "Usuario{" +
"nombre='" + nombre + '\'' +
", edad=" + edad +
", DNI='" + DNI + '\'' +
'}';
}
}
Después de eso tenemos la clase Cuenta
que como lo solicita el ejercicio va a recibir un Usuario
:
class Cuenta {
private double saldo;
private Usuario usuario;
private List<Gasto> gastos;
private List<Ingreso> ingresos;
public Cuenta(Usuario usuario) {
this.usuario = usuario;
this.saldo = 0;
this.gastos = new ArrayList<>();
this.ingresos = new ArrayList<>();
}
public double getSaldo() {
return saldo;
}
public void setSaldo(double saldo) {
this.saldo = saldo;
}
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
public double addIngresos(String description, double cantidad) {
this.setSaldo(this.getSaldo() + cantidad);
this.ingresos.add(new Ingreso(cantidad, description));
return this.getSaldo();
}
public double addGastos(String description, double cantidad) throws GastoException {
if (this.getSaldo() < cantidad) {
throw new GastoException();
}
this.setSaldo(this.getSaldo() - cantidad);
this.gastos.add(new Gasto(cantidad, description));
return this.getSaldo();
}
public List<Gasto> getGastos() {
return gastos;
}
public List<Ingreso> getIngresos() {
return ingresos;
}
@Override
public String toString() {
return "Cuenta{" +
"saldo=" + saldo +
", usuario=" + usuario +
", gastos=" + gastos +
", ingresos=" + ingresos +
'}';
}
}
Fíjate en la línea 37. Dentro de ella estamos lanzando la excepción GastoException
como lo solicita el ejercicio, misma que es una excepción personalizada de Java y se ve así:
class GastoException extends Exception {
public GastoException() {
}
}
El código completo de todas las clases junto con el método Main que usa un poco de ellas (no todo, pues como te lo dije, no he implementado el menú) queda así:
import java.util.ArrayList;
import java.util.List;
abstract class Dinero {
private double dinero;
private String description;
public double getDinero() {
return dinero;
}
public void setDinero(double dinero) {
this.dinero = dinero;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
class Gasto extends Dinero {
public Gasto(double gasto, String description) {
this.setDinero(gasto);
this.setDescription(description);
}
@Override
public String toString() {
return this.getDescription() + " " + this.getDinero();
}
}
class Ingreso extends Dinero {
public Ingreso(double ingreso, String description) {
this.setDinero(ingreso);
this.setDescription(description);
}
@Override
public String toString() {
return this.getDescription() + " " + this.getDinero();
}
}
class Usuario {
private String nombre;
private int edad;
private String DNI;
public Usuario() {
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getEdad() {
return edad;
}
public void setEdad(int edad) {
this.edad = edad;
}
public String getDNI() {
return DNI;
}
public boolean setDNI(String DNI) {
// Solo puede medir 9 (sin guión) o 10 (con guión)
if (DNI.length() != 9 && DNI.length() != 10) {
return false;
}
// Si mide 10, debe tener un guión en la posición 8
if (DNI.length() == 10) {
// Extraerlo y regresar false si no es un guión
String posibleGuion = String.valueOf(DNI.charAt(8));
if (!posibleGuion.equals("-")) {
return false;
}
}
// Hasta ahora sabemos que mide 9 o 10 y que el guión es válido (esté presente o no)
String primerosOcho = DNI.substring(0, 8);
String ultimo = String.valueOf(DNI.charAt(DNI.length() - 1));
// Comprobar que los primeros 8 sean numéricos
if (!primerosOcho.matches("[0-9]+")) {
return false;
}
// Comprobar que el último sea una letra
if (!ultimo.matches("[A-Z]+")) {
return false;
}
// Si llegamos hasta aquí y no regresamos arriba, entonces el DNI es válido
this.DNI = DNI;
return true;
}
@Override
public String toString() {
return "Usuario{" +
"nombre='" + nombre + '\'' +
", edad=" + edad +
", DNI='" + DNI + '\'' +
'}';
}
}
class Cuenta {
private double saldo;
private Usuario usuario;
private List<Gasto> gastos;
private List<Ingreso> ingresos;
public Cuenta(Usuario usuario) {
this.usuario = usuario;
this.saldo = 0;
this.gastos = new ArrayList<>();
this.ingresos = new ArrayList<>();
}
public double getSaldo() {
return saldo;
}
public void setSaldo(double saldo) {
this.saldo = saldo;
}
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
public double addIngresos(String description, double cantidad) {
this.setSaldo(this.getSaldo() + cantidad);
this.ingresos.add(new Ingreso(cantidad, description));
return this.getSaldo();
}
public double addGastos(String description, double cantidad) throws GastoException {
if (this.getSaldo() < cantidad) {
throw new GastoException();
}
this.setSaldo(this.getSaldo() - cantidad);
this.gastos.add(new Gasto(cantidad, description));
return this.getSaldo();
}
public List<Gasto> getGastos() {
return gastos;
}
public List<Ingreso> getIngresos() {
return ingresos;
}
@Override
public String toString() {
return "Cuenta{" +
"saldo=" + saldo +
", usuario=" + usuario +
", gastos=" + gastos +
", ingresos=" + ingresos +
'}';
}
}
class GastoException extends Exception {
public GastoException() {
}
}
public class Main {
public static void main(String[] args) {
Usuario usuario = new Usuario();
usuario.setNombre("Luis");
usuario.setEdad(24);
boolean ok = usuario.setDNI("12345678A");
Cuenta cuenta = new Cuenta(usuario);
System.out.println(cuenta);
}
}
Como siempre te digo: eres libre de descargar, mejorar y modificar el código. También te dejo con más artículos de programación en Java para que aprendas más sobre este lenguaje.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.