Hoy me has cogido con ganas de escribir. Te comento cosas que he ido viendo:
Punto 1 clase legislador:
Es recomendable usar siempre la estructura:
[modificador de acceso] [abstract] {class | interface | enum} NombreClase [extends + ClasePadre] [implements + Interfaz1,...,interfazN]{...}
por ejemplo:
public abstract class VehiculoPolicia extends Vehiculo implements Serializable,Cloneable{...}
En tu caso, has cambiado el orden y has echo:
abstract public class Legislador extends Persona{ ... }
Como comento, se recomienda el modificador de acceso primero.
Punto 2 sobre las clases Repite, Centrar, Enmarcar, Mensa.
Creo que todas tienen métodos similares y ademas veo que las vas usando de un proyecto a otro, no te sería mas sencillo crear una clase llamada por ejemplo... UtilConsola y arrejuntar ahí todas estas funciones y cuando quieras hacer uso de alguno de sus métodos solo tendrás una clase para manejar y no 5 distintas...?? no se, es algo que yo haría.
Por otro lado la clase Repite es exactamente igual que el método repite de la clase Enmarcar. Existen una serie de principios en el ámbito de la programación y uno de los mas básicos es el principio DRY(Dont repeat yourself), viene a decir que no te repitas a ti mismo.
Entre estas dos clases, no se cumple este principio, por tanto creo que uno de los dos métodos te sobra.
Esta bien estas clases útiles que te estas creando, pero creo que deberías darles un repaso y aglutinar los métodos similares en una misma clase, ademas por lo que veo son todas con métodos static, por lo que aglutinarlas como te digo en una clase UtilConsola o algo así, te facilitaría saber si estas repitiendo código o funcionalidad como te esta pasando ahora.
La clase Per, que supongo es para calcular un porcentaje...Veo que la usas tanto para diputados como para senadores, y supongo que has creado la clase con intención de usarla en el futuro, Si es así deberías ponerle un nombre mas definido por ejemplo(UtilMatematicas) y ahí empezaras a crear funciones que te puedan resultar útil a lo largo de tu vida de desarrollador. La verdad ejk Per... nose, jaja.
Punto 3 en la clase Persona, me encuentro esto:
public void mostrarDatos() {
String nombre = "Nombre: ",apellidos = "Apellidos: ",edad = "Edad: ";
System.out.println(Repite.charNum(' ',40-nombre.length())+nombre+this.nombre);
System.out.println(Repite.charNum(' ',40-apellidos.length())+apellidos+this.apellidos);
System.out.println(Repite.charNum(' ',40-edad.length())+edad+this.edad+" años");
}
public String toString() {
Integer datoEdad = edad;
return "-Nombre: ".concat(nombre).concat(" -Apellidos: ").concat(apellidos).
concat(" -Edad: ").concat(datoEdad.toString());
}
A ver te explicaré algo que no se si sabrás, toString() es un método especial que se hereda de la clase Object(Clase padre de todas), cuando lo escribes en una clase, lo estas sobrescribiendo de la clase Object o alguna otra intermedia, por tanto debería tener anotación @Override. Al margen de esto como te decía es un método especial que se invoca cuando intentas imprimir por pantalla,escribir a un fichero,... Un objeto de ese tipo al que le has implementado el método toString().
Un ejemplo: Tenemos tu clase persona, pues te creare una clase TestPersona para que entiendas de lo que te hablo.
public class TestPersona {
public static void main(String[] arg ){
Persona p1=new Persona("pepe","gonzalez",55);
System.out.println(p1);
}
}
Y la salida que se obtiene:
run:
-Nombre: pepe -Apellidos: gonzalez -Edad: 55
BUILD SUCCESSFUL (total time: 0 seconds)
Si te fijas lo que he echo, es imprimir directamente una variable persona, y que es lo que ha pasado? Pues que automáticamente java ha buscado en la clase Persona si existía el método toString(), al existir, lo ha invocado y ha mostrado por pantalla el String que devuelve este método.
Si no lo hubiera encontrado, habría ido a la clase padre a buscarlo. Por ejemplo si creo un objeto de tipo Diputado y lo intento imprimir por pantalla como no tiene método toString, va a la clase padre(Legislador) a buscarlo, como tampoco lo tiene va a su clase padre(Persona) y aquí lo encuentra, lo invoca, y se muestra por pantalla, por tanto si hacemos:
public class TestPersona {
public static void main(String[] arg ){
Diputado dip= new Diputado("pepe","gonzalez",55,"cadiz");
System.out.println(dip);
}
}
La salida por pantalla sera la misma que si fuera una persona:
run:
-Nombre: pepe -Apellidos: gonzalez -Edad: 55
BUILD SUCCESSFUL (total time: 0 seconds)
Por tanto con lo que tu has echo de escribir el método toString y ademas el mostrarDatos(), rompe de nuevo con el principio DRY, por eso te recomiendo solo que te curres el método toString() y lo uses para imprimir datos de una persona o legislador, o el objeto para el que tu quieras poder imprimirlo directamente.Por lo que yo modificaría tu clase persona para que quedara de la siguiente forma el método toString() y nos ahorraríamos el mostrar datos.
@Override
public String toString() {
String nombre = "Nombre: ",apellidos = "Apellidos: ",edad = "Edad: ";
String cadena=Repite.charNum(' ',40-nombre.length())+nombre+this.nombre+"\n"
+Repite.charNum(' ',40-apellidos.length())+apellidos+this.apellidos+"\n"
+Repite.charNum(' ',40-edad.length())+edad+this.edad+" años";
return cadena;
}
Y con esto obtendrías la misma salida que con el método mostrarDatos(). De esta manera con un simple "System.out.println(variable_tipo_persona);" se imprimiría por pantalla el objeto de tipo persona con el formato que tenia en el mostrarDatos().
nota:En caso de necesitar disponer de distintos formatos de impresión, entonces si habría que crear distintos métodos para los distintos formatos. Y entonces lo tuyo si estaría bien.
Punto 4En mi opinión, creo que si ordenaras un poco mas las cosas podrías crear cosas mas eficientes, por ejemplo el método buscar de la clase ListinLegislador. Creo que no deberia ser tan intrincado, yo por ejemplo crearía un método que devolviera un nuevo arrayList con los elementos encontrados en la búsqueda(Si puede haber mas de 1) o un objeto de tipo legislador(si solo puede haber 1) y con ese array o variable mostrar los resultados, pero eso de mezclar: "entrada de consola- proceso de búsqueda- salida por consola y tratamiento de resultado" en un mismo método no es muy recomendable.
Yo tendría por ejemplo:
- Un método que obtenga la entrada de teclado del usuario(datos para realizar la búsqueda).
- Otro método que generara un nuevo arraylist con los resultados de la búsqueda de acuerdo a ciertos parámetros.
- Y otro método que reciba un parámetro(arraylist que será el devuelto por el método anterior).Este método se encargara de generar la salida y tratar la interacción con el usuario .
Intentar modularizar en distintos pasos, sin pasarse tampoco... No es cuestión de tener 300 métodos cada uno para una instrucción...XDD pero si es recomendable intentar separar las distintas fases de una acción. En el caso que te explicado anteriormente, las fases podrían ser:
- Obtener los datos para la búsqueda.
- Realizar la búsqueda.
- Tratar el resultado.
Es recomendable hacer esto por claridad y dar posibilidad a poder REUTILIZAR CÓDIGO. Imagina que te has currado este programa para una empresa, y al mes de entregarlo, tu jefe te dice: Oye que ahora en lugar de trabajar a través de la consola, queremos la misma funcionalidad pero en un JFrame(Ventana). Pues en este caso tendrías que crear otro método buscar totalmente diferente desde cero, ya que el que tu tenias estaba echo solo para consola.
Ahora imagina que habías realizado esta separación que te he comentado, pues si lo hubieras echo, el método buscar te lo ahorrarías ya que el anterior te vale, solo tendrias que modificar los métodos para obtener los datos para la búsqueda y el método para tratar el resultado a través de una interfaz gráfica, pero el método buscar seguiría siendo el mismo. Esto es simplemente un ejemplo, y al principio cuesta el separar las funciones pero poco a poco te irás acostumbrando.
Punto 5 En cuanto a tu clase validador, jeje esta bastante bien, "modo javascript onkeypress ON" XDD. te escribo una alternativa a tus métodos para que veas una forma rápida y fácil de validar. Hace uso de bloques try-catch, pero tampoco tienen mucha complicacion, simplemente intento convertir la cadena a int o float, si se convierte bien, es que la cadena era un numero valido y devuelve true. Si no se convierte, se lanza la excepción NumberFormatException y entonces se devuelve false. Como ves te ahorras bastantes if y bucles...
public class ValidadorNumero {
public static boolean validarNumeroEntero(String numero){
try{
int n=Integer.parseInt(numero);//intento convertir cadena a entero
return true; //Si se consigue
}
catch(NumberFormatException e){
return false; //Si no se consigue
}
}
public static boolean validarNumeroEntero(String numero,int valorInicial, int valorFinal){
try{
int n=Integer.parseInt(numero); //intento convertir cadena a entero
if(n>valorFinal || n< valorInicial){
throw new NumberFormatException("numero fuera de rango"); //Si esta fuera de rango, lanzo una excepcion NumberFormatException
}
return true; // si se consigue y el numero esta en el rango
}
catch(NumberFormatException e){
return false; //Si no se consigue o el numero no esta en el rango
}
}
public static boolean validarFloat(String numero){
try{
float n=Float.parseFloat(numero);//intento convertir cadena a float
return true; //Si se consigue
}
catch(NumberFormatException e){
return false; //Si no se consigue
}
}
public static void main(String[] arg){
System.out.println(" Validando enteros:");
System.out.println("1331231 es entero: "+validarNumeroEntero("1331231"));
System.out.println("sgf231 es entero: "+validarNumeroEntero("sgf231"));
System.out.println(" Validando enteros con rangos 0-100:");
System.out.println("12 es entero entre 0 y 100: "+validarNumeroEntero("12",0,100));
System.out.println("155 es entero entre 0 y 100: "+ validarNumeroEntero("155",0,100));
System.out.println(" Validando floats:");
System.out.println("12.35 es float: "+validarFloat("12.35"));
System.out.println("12..5 es float: "+validarFloat("12..5"));
}
}
Como ves, de esta forma ahorras muchas operaciones al procesador y sobre todo te ahorras mucho código. Por cierto, en tu clase Validador vuelves a romper con el principio DRY en los métodos:
- public static int entero (String entrada, int valorInicial, int valorFinal) {
- public static int entero (String entrada) {
En el método "public static int entero (String entrada, int valorInicial, int valorFinal) {" podrias haber echo uso del otro método de esta manera:
public static int entero (String entrada, int valorInicial, int valorFinal) {
int entero = Validador.entero(entrada);
if (entero < valorInicial || entero >= valorFinal) {
return valorInicial - 1;
}
else{
return entero;
}
}
Te hubieras ahorrado hacer 2 métodos prácticamente iguales como te ha pasado. A veces perder 30 minutos en la planificación de un ejercicio, ahorra 1 hora en el desarrollo del mismo... XDD
Y nada ahí tienes para entretenerte, aburrirte y todo lo que quieras y aun así seguro que me dejo algo detrás. Aunque veas que escribo mucho, comentarte que en general tu ejercicio esta bien, y todo lo que te comento son simples recomendaciones para mejorar el orden, eficiencia y claridad. Si no entiendes alguna cosilla ya sabes que por aquí andamos, Un saludo.