Vamos comentando algunas cosas.
Primero, en la clase Contacto te falta el atributo de ID. Has de incluirlo si luego en el programa queremos buscar contactos por ID.
Otra opcion sería prescindir del ID y buscar por nombre, pero casi queda mejor hacerlo usando un atributo ID.
Segundo, el arreglo lo has declarado de tipo Object. Esto, funciona bien, pero no es lo ideal.
El tipo Object, es algo así como la clase "universal" de Java, todas las clases, incluso las creadas por ti mismo... heredan de la clase Object automaticamente, sin necesidad de indicarlo en ninguna parte.
Esto significa que en ese arreglo, puedes meter objeto de las clases Persona y Empresa sin problemas. Pero también significa que podrías meter un objeto String, un objeto Scanner, un objeto JButton, un objeto JPanel, un objeto Random, un objeto Date.... en definitiva, en ese arreglo se puede meter CUALQUIER cosa.
Lo ideal es limitarlo a las clases con las que queremos trabajar. Estas clases son Persona y Empresa, que todas ellas heredan de la clase abstracta Contacto.
Así que para ello, el arreglo interesa declararlo como de tipo Contacto, esto nos permite meter Personas y Empresas en ese arreglo, y nada más.
Sobre el menu, si queremos que salga varias veces hasta que el usuario decida terminar el programa, no queda otra que incluirlo dentro del bucle.
Puesto que la opción para finalizar el programa es que el usuario introduzca un 5, pues la condición del bucle es que se repita
mientras la opcion sea distinta de 5Sobre el código que estamos escribiendo, siempre es mejor dividirlo en porciones, usando varios métodos, de manera que el main quede reducido al menor número de lineas posibles.
Esto además es útil para que el código sea más legible y nos es más fácil aclarar ideas, pues muchas veces nos atascamos porque tenemos en pantalla tal cantidad de lineas e instrucciones, que la cabeza se nos embota...
Se puede hacer un método que se encargue únicamente de mostrar el menú. No hará nada más, solo eso, mostrar el menú.
Por ejemplo:
static void mostrarMenu()
{
System.out.println("\n");
System.out.println(" 1 - Agregar contacto");
System.out.println(" 2 - Buscar contacto por ID");
System.out.println(" 3 - Editar contacto");
System.out.println(" 4 - Mostrar todos los contactos");
System.out.println(" 5 - Salir\n");
}
Los "\n" es para que haga saltos de linea, asi cada vez que se escriba el menu en pantalla saldrá algo separado del texto de la anterior operacion que hubieramos hecho.
Como ves, es un método muy simple, tan solo escribe lineas de texto en pantalla.
Pero al ponerlo por separado, permite reducir lineas en el main, ya que nos bastará una sola linea para llamarlo en lugar de tener que poner las 6 lineas necesarias para escribir el menu.
Luego, podemos hacer otro método que se encargue de pedir la opcion, y de hecho podemos hacer que sea de tipo boolean, de manera que solo devuelva
true si se ha introducido una opción válida (numero de 1 a 5).
Si se introduce cualquier otro numero, o una letra, devolverá
false y podemos hacer que se repita la petición de la opción mientras este método devuelva
falseEste podría ser el método para pedir la opcion:
static boolean pedirOpcion()
{
try
{
System.out.print("\nIntroduzca opcion: ");
opcion = sc.nextInt(); sc.nextLine();//Tras leer valores numericos, interesa hacer un nextLine() para limpiar el stream.
if (opcion >= 1 && opcion <= 5)
return true;//Ha introducido una opcion valida
else
{
System.out.println("Error. Solo se admite valor entre 1 y 5.");
return false;//Opcion invalida
}
}
catch(Exception e)
{
sc.nextLine();//De nuevo, es necesario limpiar el stream
System.out.println("Error. Introduzca solo numeros, entre 1 y 5.");
return false;//Ha introducido letras o simbolos, no números, lo cual provoca una excepcion
}
}
Aquí a lo mejor te parece un poco raro eso de hacer "un nextLine() para limpiar el stream".
La clase Scanner es un poco imperfecta, y tras leer valores numéricos, conviene hacer un nextLine() (sin asignar a ninguna variable) si luego queremos leer datos de tipo String (por ejemplo, nombres).
En este otro
hilo lo explico un poco más a fondo.
Si quieres ver uno de los problemas que puede ocasionar, cuando el programa ya esté terminado, quita por ejemplo el nextLine() que hay dentro del
catch, ejecuta el programa y mete una letra para forzar que ocurra la excepción por no haber metido un numero.
Verás la diferencia entre poner y no poner ese nextLine() que, aparentemente, no parece hacer nada útil....
Y ya puestos, podemos (casi que debemos) hacer un método para cada una de las opciones del menú: mostrar contacto, editar, listar....
Al dividir todo el programa en pequeños métodos (es lo que se llama
programación modular), verás que el metodo principal main queda mucho más legible.
Y en caso de cometer algún error u olvidar algo, es mucho más fácil encontrar donde está el error/olvido ya que podemos irnos directamente al método en cuestión, en lugar de tener que recorrer arriba y abajo un metodo main enorme con cientos de lineas.
Si lo dividimos todo en pequeños métodos, que es lo ideal, surge un pequeño problema.
La mayoría de estos métodos necesitan que el arreglo de Contacto y el objeto Scanner para leer datos por teclado estén visibles para ellos.
Si declaramos el arreglo y el Scanner dentro del método main, como has hecho en tu código, estos métodos no podrán verlos, y no podrán acceder a ellos.
Para hacer que si sean visibles y cualquier método tenga acceso a ellos, tenemos que declararlos fuera del main, los declararemos como atributos de la clase Prueba.
Y han de ser declarados con la palabra reservada
static, puesto que el main y el resto de método también serán
estaticos.
Otras variables, como el int donde guardamos la opcion escogida por el usuario o la que nos dice hasta que posicion del arreglo tenemos Contactos registrados, también necesitarmos que sean visibles para varios métodos.
Si ahora mismo no tienes claro la diferencia entre
estatico y
no-estatico, no importa, podemos hablar de eso después. De momento centrémonos en hacer funcionar este programa.
Bien, mira, te dejo aquí una nueva clase Prueba, ya organizada, pero sin terminar.
package agendaContactos;
import java.util.Scanner;
public class Prueba {
static Scanner sc = new Scanner(System.in);
static Contacto agenda[] = new Contacto[50];
static int opcion = 0;
static int indiceArreglo = 0;
public static void main(String[] args) {
do{
mostrarMenu();
while(pedirOpcion() == false);
switch(opcion)
{
case 1:
nuevoContacto();
break;
case 2:
buscarContacto();
break;
case 3:
editarContacto();
break;
case 4:
listarContactos();
break;
case 5:
System.out.println("FIN DEL PROGRAMA");
}
}while(opcion != 5);
}//Fin del metodo main()
static void mostrarMenu()
{
System.out.println("\n");
System.out.println(" 1 - Agregar contacto");
System.out.println(" 2 - Buscar contacto por ID");
System.out.println(" 3 - Editar contacto");
System.out.println(" 4 - Mostrar todos los contactos");
System.out.println(" 5 - Salir\n");
}
static boolean pedirOpcion()
{
try
{
System.out.print("\nIntroduzca opcion: ");
opcion = sc.nextInt(); sc.nextLine();//Tras leer valores numericos, interesa hacer un nextLine() para limpiar el stream.
if (opcion >= 1 && opcion <= 5)
return true;//Ha introducido una opcion valida
else
{
System.out.println("Error. Solo se admite valor entre 1 y 5.");
return false;//Opcion invalida
}
}
catch(Exception e)
{
sc.nextLine();
System.out.println("Error. Introduzca solo numeros, entre 1 y 5.");
return false;//Ha introducido letras o simbolos, no números, lo cual provoca una excepcion
}
}
static void nuevoContacto()
{
if (indiceArreglo == 50)
System.out.println("\nLa Agenda esta llena. No caben nuevos contactos");
else
{
System.out.print("\nIndique si es una (E)mpresa o una (P)ersona (E/P): ");
char opcion = sc.nextLine().toUpperCase().charAt(0);
switch (opcion)
{
case 'E':
agenda[indiceArreglo] = pedirDatosEmpresa();
indiceArreglo++;
break;
case 'P':
agenda[indiceArreglo] = pedirDatosPersona();
indiceArreglo++;
break;
default:
System.out.println("No se reconoce la opcion indicada: " + opcion);
}
}
}
static Persona pedirDatosPersona()
{
System.out.print("\nIntroduzca ID: ");
int id = sc.nextInt(); sc.nextLine();
System.out.print("Introduzca Nombre: ");
String nombre = sc.nextLine();
System.out.print("Introduzca E-Mail: ");
String email = sc.nextLine();
System.out.print("Introduzca DNI: ");
String dni = sc.nextLine();
System.out.print("Introduzca numero celular: ");
String celular = sc.nextLine();
return new Persona(id, nombre, email, dni, celular);
}
static Empresa pedirDatosEmpresa()
{
System.out.print("\nIntroduzca ID: ");
int id = sc.nextInt(); sc.nextLine();
System.out.print("Introduzca Nombre: ");
String nombre = sc.nextLine();
System.out.print("Introduzca numero tlf fijo: ");
String fijo = sc.nextLine();
System.out.print("Introduzca URL pagina web: ");
String web = sc.nextLine();
System.out.print("Introduzca numero empresa: ");
String nEmpresa = sc.nextLine();
return new Empresa(id, nombre, fijo, web, nEmpresa);
}
static void buscarContacto()
{
/*
* Comprobar si existe al menos un contacto registrado.
* Pista: Si indiceArreglo == 0, es que aún no hay Contactos registrados.
* Si hay contactos en el arreglo:
* Pedir ID del contacto que se quiere editar.
* Recorrer arreglo hasta encontrar el Contacto con dicho ID
* o hasta donde indique indiceArreglo, ya que quizás nos han dado un ID que no existe.
*
* Si se encuentra el Contacto, comprobar si es una instancia de Persona o Empresa,
* hacer casting a la clase que corresponda y mostrar su datos actuales.
* Pista: la instruccion instanceof nos dice cual es la clase con la que se instancio un objeto
*/
}
static void editarContacto()
{
/*
* Comprobar si existe al menos un contacto registrado.
* Pista: Si indiceArreglo == 0, es que aún no hay Contactos registrados.
* Si hay contactos en el arreglo:
* Pedir ID del contacto que se quiere editar.
* Recorrer arreglo hasta encontrar el Contacto con dicho ID
* o hasta donde indique indiceArreglo, ya que quizás nos han dado un ID que no existe.
*
* Si se encuentra el Contacto, comprobar si es una instancia de Persona o Empresa,
* hacer casting a la clase que corresponda y mostrar su datos actuales.
* Pista: la instruccion instanceof nos dice cual es la clase con la que se instancio un objeto
*
* Decidir si:
* (Proceso fácil y rápido)
* - Pedimos todos los datos completos otra vez y directamente sustituimos el contacto en la posicion del arreglo
* donde encontramos el contacto que se quiere editar.
* Se puede reaprovechar los métodos pedirDatosPersona() y pedirDatosEmpresa()
*
* (Proceso un poco más complejo)
* - Preguntamos al usuario que atributo quiere modificar y solo nos ocupamos de ese atributo.
* ESto es más complejo porque habría que mostrar nuevos submenus, distintos si es una Persona o una Empresa
* y hacer más switch para ver que atributo se ha decidido modificar.
*/
}
static void listarContactos()
{
/*
* Recorrer arreglo, hasta donde indique la variable indiceArreglo
* y mostrar los datos de cada Contacto.
*/
}
}
- Los objetos y variables que necesitamos sean visibles para todos los métodos, están declarados ya como atributos estáticos.
- El método principal main, está reducido a tan solo unas pocas líneas ya que todo el código importante estará separado en distintos métodos.
Consta básicamente de un bucle do..while() (es prácticamente lo mismo que un while()) que se repetirá hasta que el usuario meta un 5 como ocpion.
Cada vez que se repite:
- llama al metodo que muestra el menu.
- llama al metodo que pide opcion al usuario. Este metodo esta puesto como condicion de otro bucle while(), de este modo el metodo se repite cada vez que devuelve false.
Recuerda que si devuelve false, es porque el usuario ha introducido una opcion equivocada.
Esta linea te puede parecer un poco rara porque el metodo pedirOpcion() no está DENTRO del bucle while(), si no que está puesto como CONDICION.
Esta es una forma de simplificar el codigo, en realidad el bucle while() esta vacío, carece de cuerpo.. simplemente comprobará la CONDICION (nuestro método pedirDatos()) una y otra vez hasta que devuelva TRUE, lo que significa que el usuario introdujo una opción válida.
-Tras pedir opcion, ejecuta un switch y según la opcion introducida, llamará a los distintos métodos que se encargan de crear nuevo contacto, editar, mostrar o listar.
- Después del main, vienen los métodos.
El primero, el de dar de alta un contacto, te lo he dejado ya hecho. Fíjate que además se sirve de otros dos métodos que se dedican únicamente a pedir datos para crear y retornar un objeto Persona, o un objeto Empresa.
Luego lo comentamos un poco más a fondo. - El resto de métodos estan sin hacer, aunque he puesto comentarios sobre más o menos los pasos que habría que seguir.
Intenta hacer tu lo que puedas.
El metodo de editarContacto es cierto que es un poco más dificil que el resto, en los comentarios ya he puesto que habría que decidir entre dos formas de hacerlo, una más simple y fácil y otra un poco más complicada.
Podríamos hacer de momento la forma fácil, y una vez que esté terminado todo y funcionando, atrevernos con la forma difícil.
En realidad esta segunda forma de hacerlo no es dificil, es solo que requiere mucho más código porque habría que presentar un nuevo submenú para que el usuario decida qué atributo quiere modificar, submenús que serán distintos segun si estamos con una Empresa o una Persona..
Para no hacer posts tan grandes, debajo posteo otro mensaje explicando un poco el método
nuevoContacto()