Sistema de Gestión de Clientes en Java: Desarrollo y Funcionalidades Esenciales
Enviado por Chuletator online y clasificado en Informática y Telecomunicaciones
Escrito el en español con un tamaño de 15,57 KB
Introducción al Sistema de Gestión de Clientes en Java
Este documento detalla la implementación de una aplicación en Java diseñada para la gestión eficiente de clientes de una empresa. El sistema permite almacenar y manipular datos clave de los clientes, como su NIF, nombre, teléfono y deuda, utilizando una estructura de datos dinámica para optimizar el rendimiento y la escalabilidad.
Objetivos del Proyecto
El propósito principal de esta aplicación es proporcionar una interfaz sencilla y funcional para las siguientes operaciones:
- Añadir cliente: Registrar nuevos clientes solicitando sus datos esenciales y almacenándolos en la estructura dinámica.
- Listar clientes: Visualizar todos los clientes registrados en el sistema, mostrando sus detalles.
- Buscar clientes: Localizar un cliente específico mediante su NIF y mostrar su nombre y teléfono.
- Calcular deuda total de la empresa: Determinar la suma de las deudas de todos los clientes.
- Modificar cliente: Actualizar la información de un cliente existente.
- Salir de la aplicación: Finalizar la ejecución del programa.
Estructura del Programa
El programa se concibe para ser modular, aunque en el código proporcionado se presenta una implementación consolidada. Idealmente, se estructuraría en tres ficheros principales para una mejor organización y mantenimiento:
- Fichero 1 (Interfaz de Usuario): Contendría la lógica para interactuar con el usuario, mostrando el menú de opciones y gestionando las entradas y salidas.
- Fichero 2 (Definición de Datos y Métodos): Aquí se definirían las clases de datos (como
Clientes
) y los métodos para las operaciones de gestión (añadir, listar, buscar, etc.). - Fichero 3 (Clase Principal/Ejecutable): Este fichero contendría el método
main
, encargado de inicializar la aplicación y llamar a los métodos de la interfaz y la lógica de negocio.
A continuación, se presenta el código Java con las correcciones y mejoras pertinentes:
package Examenes;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List; // Aunque List no se usa directamente, es buena práctica mantenerla si se piensa en interfaces.
/**
Clase que representa a un cliente y contiene la lógica para la gestión de clientes.
Idealmente, la lógica de gestión (añadir, listar, buscar, etc.) residiría en una clase separada
(por ejemplo, ClienteManager o SistemaClientes) para una mejor separación de responsabilidades.
*/
public class Clientes {
// Atributos para la lectura de entrada del usuario
private InputStreamReader isr = new InputStreamReader(System.in);
private BufferedReader br = new BufferedReader(isr);
// Esta lista 'Aprobar' no se utiliza en los métodos de instancia que reciben una lista como parámetro.
// Los métodos operan sobre la lista que se les pasa, lo cual es una buena práctica.
// Si esta clase fuera un "Gestor de Clientes", esta lista sería el almacenamiento principal.
// ArrayList<Clientes> Aprobar = new ArrayList<Clientes>(); // Se mantiene según la instrucción de no eliminar contenido.
// Atributos de un cliente
private String nombre;
private String dni; // Se usa 'dni' en el código, mientras que la descripción usa 'NIF'. Se mantiene 'dni' por consistencia con el código.
private int tlf;
private double deuda;
/**
Constructor por defecto de la clase Clientes.
*/
public Clientes() {
}
/**
Constructor parametrizado para inicializar un objeto Cliente.
@param nombre Nombre del cliente.
@param dni DNI/NIF del cliente.
@param tlf Número de teléfono del cliente.
@param deuda Deuda actual del cliente.
*/
public Clientes(String nombre, String dni, int tlf, double deuda) {
this.nombre = nombre;
this.dni = dni;
this.tlf = tlf;
this.deuda = deuda;
}
/**
Calcula la deuda total de una lista de clientes.
Nota: Existe un método 'deudaTotal' que realiza la misma función.
Se recomienda usar solo uno para evitar redundancia.
@param a La lista de clientes.
@return La suma total de las deudas.
*/
public double deuda(ArrayList<Clientes> a) {
double acum = 0;
for (int k = 0; k < a.size(); k++) {
acum += a.get(k).deuda;
}
return acum;
}
/**
Carga los datos de un nuevo cliente desde la entrada del usuario.
Realiza validación básica del DNI (longitud).
@param a La lista de clientes existente para verificar duplicados de DNI.
@return Un nuevo objeto Clientes con los datos introducidos.
@throws IOException Si ocurre un error de entrada/salida.
*/
public Clientes cargar(ArrayList<Clientes> a) throws IOException {
Clientes cl;
String nom = "";
String temp;
// String copia = ""; // Variable declarada pero no utilizada. Se mantiene por la instrucción de no eliminar contenido.
String nif = "";
int t = 0;
double d = 0;
try {
System.out.print("Introduce el nombre del Cliente: ");
nom = br.readLine();
do {
System.out.print("Introduce DNI del cliente (9 caracteres): ");
nif = br.readLine();
} while (nif.length() != 9);
// Comprobar si el DNI ya existe
for (int k = 0; k < a.size(); k++) {
if (nif.equals(a.get(k).dni)) {
System.out.println("Este Cliente ya se ha introducido.");
// copia = a.get(k).dni; // Asignación a variable no utilizada.
break;
}
}
System.out.print("Introduce Teléfono: ");
temp = br.readLine();
t = Integer.parseInt(temp);
System.out.print("Introduce deuda: "); // Corregido de println a print
temp = br.readLine();
d = Double.parseDouble(temp);
} catch (NumberFormatException e) {
System.out.println("Error de formato numérico: " + e.getMessage());
}
cl = new Clientes(nom, nif, t, d);
return cl;
}
/**
Añade un nuevo cliente a la lista.
@param a La lista de clientes a la que añadir.
@throws IOException Si ocurre un error de entrada/salida durante la carga.
*/
public void cargarArrayList(ArrayList<Clientes> a) throws IOException {
a.add(cargar(a));
}
/**
Muestra los detalles de un cliente específico en la consola.
@param a La lista de clientes.
@param b El índice del cliente a mostrar.
*/
public void ver(ArrayList<Clientes> a, int b) {
// Añadidos espacios para una mejor legibilidad en la salida
System.out.println("Nombre: " + a.get(b).nombre + " DNI: " + a.get(b).dni + " Teléfono: " + a.get(b).tlf + " Deuda: " + a.get(b).deuda);
}
/**
Muestra los detalles de todos los clientes en la lista.
@param a La lista de clientes.
*/
public void verTodos(ArrayList<Clientes> a) {
if (a.isEmpty()) {
System.out.println("No hay clientes registrados.");
return;
}
for (int k = 0; k < a.size(); k++) {
System.out.println("Nombre: " + a.get(k).nombre + " DNI: " + a.get(k).dni + " Teléfono: " + a.get(k).tlf + " Deuda: " + a.get(k).deuda);
}
}
/**
Calcula la deuda total de la empresa sumando las deudas de todos los clientes.
@param a La lista de clientes.
@return La deuda total de la empresa.
*/
public double deudaTotal(ArrayList<Clientes> a) {
double deudaAcumulada = 0; // Renombrado para mayor claridad
for (int k = 0; k < a.size(); k++) {
deudaAcumulada += a.get(k).deuda;
}
return deudaAcumulada;
}
/**
Busca un cliente por su DNI/NIF en la lista.
@param a La lista de clientes donde buscar.
@return El índice del cliente si se encuentra, o -1 si no.
@throws IOException Si ocurre un error de entrada/salida.
*/
public int buscar(ArrayList<Clientes> a) throws IOException {
String d = "";
int bus = -1;
System.out.print("Introduce DNI a buscar: ");
// El try-catch para NumberFormatException no es necesario aquí, ya que readLine() no lanza esa excepción.
// Se ha eliminado el bloque try-catch innecesario.
d = br.readLine();
for (int k = 0; k < a.size(); k++) {
if (d.equals(a.get(k).dni)) {
bus = k;
break;
}
}
return bus;
}
/**
Permite al usuario seleccionar y modificar un campo específico de un cliente.
@param a La lista de clientes.
@param b El índice del cliente a modificar.
@return Un nuevo objeto Clientes con los datos actualizados.
@throws IOException Si ocurre un error de entrada/salida.
*/
public Clientes cargarActualizar(ArrayList<Clientes> a, int b) throws IOException {
Clientes cl;
String nom = a.get(b).nombre;
String temp;
String d = a.get(b).dni;
int t = a.get(b).tlf;
double de = a.get(b).deuda;
int op = 0;
System.out.println("Seleccione campo a modificar: ");
System.out.print("1. Nombre \n2. DNI \n3. Teléfono \n4. Deuda \nOpción: "); // Corregido "3Teléfono" y "Opcion"
temp = br.readLine();
try {
op = Integer.parseInt(temp);
switch (op) {
case 1:
System.out.print("Introduce el nuevo nombre: ");
nom = br.readLine();
break;
case 2:
do {
System.out.print("Introduce el nuevo DNI (9 caracteres): ");
d = br.readLine();
} while (d.length() != 9); // Corregido: 'temp' a 'd'
break;
case 3:
System.out.print("Introduce el nuevo teléfono: ");
temp = br.readLine();
t = Integer.parseInt(temp);
break;
case 4:
System.out.print("Introduce la nueva deuda: "); // Corregido de println a print
temp = br.readLine();
de = Double.parseDouble(temp);
break;
default:
System.out.println("Opción no válida.");
break;
}
} catch (NumberFormatException e) {
System.out.println("Error: Entrada no numérica para la opción o el valor. " + e.getMessage());
}
cl = new Clientes(nom, d, t, de);
return cl;
}
/**
Actualiza un cliente existente en la lista con los nuevos datos.
@param a La lista de clientes.
@param b El índice del cliente a actualizar.
@throws IOException Si ocurre un error de entrada/salida durante la actualización.
*/
public void cargarArrayListActualizar(ArrayList<Clientes> a, int b) throws IOException {
// Se pasa el índice 'b' directamente a cargarActualizar, evitando una nueva búsqueda innecesaria.
a.set(b, cargarActualizar(a, b));
}
/**
Muestra el menú principal de la aplicación y gestiona las operaciones.
@param a La lista de clientes sobre la que operar.
@throws IOException Si ocurre un error de entrada/salida.
*/
public void menú(ArrayList<Clientes> a) throws IOException {
// String nom="",dni="", temp; // Variables no utilizadas aquí, se eliminan para claridad.
// int tlf, deuda; // 'deuda' debería ser double si se usa, pero no se usa aquí.
int op = 0;
do {
System.out.println("\n--- MENÚ DE GESTIÓN DE CLIENTES ---");
System.out.println("1. Añadir cliente");
System.out.println("2. Listar clientes");
System.out.println("3. Deuda total de la empresa");
System.out.println("4. Buscar cliente");
System.out.println("5. Modificar cliente");
System.out.println("6. Salir de la aplicación");
System.out.print("Selecciona una opción: ");
String tempInput; // Variable temporal para la lectura
try {
tempInput = br.readLine();
op = Integer.parseInt(tempInput);
} catch (NumberFormatException e) {
System.out.println("Error: Por favor, introduce un número válido para la opción. " + e.getMessage());
op = 0; // Reiniciar opción para que el bucle continúe
continue; // Saltar al siguiente ciclo del bucle
}
switch (op) {
case 1:
cargarArrayList(a);
System.out.println("Cliente añadido correctamente.");
break;
case 2:
verTodos(a);
break;
case 3:
System.out.println("Deuda total de la empresa: " + deudaTotal(a));
break;
case 4:
int b = buscar(a);
if (b != -1) {
ver(a, b);
} else {
System.out.println("El DNI no se encuentra.");
}
break;
case 5:
int c = buscar(a); // Se busca el cliente a modificar
if (c != -1) {
cargarArrayListActualizar(a, c); // Se usa el índice 'c' encontrado
System.out.println("Cliente modificado correctamente.");
} else {
System.out.println("El DNI no se encuentra.");
}
break;
case 6:
System.out.println("Saliendo de la aplicación. ¡Hasta pronto!");
break;
default:
System.out.println("Opción no válida. Por favor, selecciona un número del 1 al 6.");
break;
}
} while (op != 6);
}
}
Consideraciones Adicionales y Mejoras Potenciales
- Separación de Responsabilidades: Para un diseño más robusto y mantenible, se recomienda separar la clase
Clientes
(que debería ser un POJO - Plain Old Java Object - solo con datos y getters/setters) de la lógica de gestión (CRUD y menú). Una claseClienteManager
oSistemaClientes
sería más adecuada para manejar laArrayList<Clientes>
y los métodos de operación. - Manejo de Excepciones: Aunque se incluyen bloques
try-catch
, se podría refinar el manejo de excepciones para proporcionar mensajes más específicos al usuario y evitar que la aplicación se detenga inesperadamente. - Validación de Entrada: La validación del DNI se limita a la longitud. Se podría implementar una validación más completa (formato de 8 dígitos + letra, letra correcta para el DNI, etc.).
- Persistencia de Datos: Actualmente, los datos se pierden al cerrar la aplicación. Para un sistema real, sería fundamental implementar la persistencia de datos, ya sea en ficheros (CSV, JSON, binario) o en una base de datos.
- Interfaz de Usuario: Para aplicaciones más complejas, se podría considerar una interfaz gráfica de usuario (GUI) en lugar de la consola.
Este sistema de gestión de clientes en Java proporciona una base sólida para el desarrollo de aplicaciones empresariales, destacando la importancia de las estructuras de datos dinámicas y la interacción con el usuario.