Estupendo, ahora si estas aplicando el polimorfismo correctamente en la clase ListaDeProductosParaEnviar.
Sobre si crear una clase padre cuando hay atributos en común entre varias clases, has llegado a una buena conclusión, esto como bien has concluido es circunstancial y dependerá de la forma en que te indiquen hacerlo o de la manera que tu creas mas conveniente, y creas que te resultara mas fácil, si es cierto que ahora que estas aprendiendo conviene que lo apliques siempre que tengas ocasión, para aprender a trabajar con herencia.
Como práctica y aprendizaje pues no te viene mal usar la herencia cuando tengas oportunidad. Normalmente en ejercicios de este tipo pues no se puede exigir mucho y de hay que una herencia para dos clases(ProdRefrigeradoOCongelado) este bien como didáctica.
Pero en mi opinión(ya que tengo poca experiencia profesional) normalmente la herencia
se suele usar para crear sistemas mas complejos, o por ejemplo la escalabilidad del código(un sistema que se prevee que va a ser ampliable)...
te voy a contar un cuento(por supuesto inventado...) de esto que te hablo:
Imagina que te contrata la universidad de biología, y te dice, queremos un programa para manejar anfibios, que me permita tener una base de datos de anfibios, poder añadir, poder consultar, etc... y te acaban diciendo y si nos gusta, quizá te contratemos para uno de mamíferos.
Caso del Programador inexperto(No piensa, no reflexiona)
Entonces tu como programador inexperto, llegas a tu casa y piensas... Jummm, me piden un programa para manejar anfibios, y directamente empiezas a crear una clase Anfibios, creas otra clase llamada ListaAnfibios, creas los jframes(ventanas) para manejar los anfibios, y te pegas 2 meses trabajando en el programa de anfibios.
Cuando lo terminas y lo entregas resulta que te dicen a pues nos encanta, haznos ahora el de mamíferos. Y el programador inexperto se tira otros 2 meses creando un programa "exactamente igual" al anterior.
Caso del Programador inteligente(piensa, reflexiona)
Entonces tu como programador inteligente, llegas a tu casa y piensas... Jummm, me piden un programa para manejar anfibios, pero también cabe la posibilidad de que me soliciten uno para mamíferos.... Pero estos tios...quizá con el tiempo también quieras uno para peces, y para aves, y quien sabe, quizá insectos...
Y piensas, pues voy a crear una clase abstracta Animales que recoja todos los datos comunes a un animal(nombre, nombre latín, procedencia, paraje, alimentación, etc) y de aquí podré ir extendiendo todos los subreinos, anfibios, mamíferos, peces, insectos, aves, por lo que si hoy me piden para anfibios, y trabajo un poco mas, si mañana me piden mamíferos tendré la mitad del trabajo echo, solo tendré que extender de la clase Animal y listo. Este me llevará tres meses pero si me piden el de mamíferos solo me llevará medio....
El programador inexperto se tiro 1 año y medio haciendo los programas para todos los reinos animales.
Y el programador inteligente hizo todos los reinos en 6 meses.
Y nada FIN! XDD
La moraleja de esto es, que a veces pensar y reflexionar antes de liarse a picar código puede mejorar mucho el diseño de nuestra aplicación.
Y bueno esto iba por lo de la herencia XDD, como ves el programador inteligente, previno una posible escalabilidad del código y el inexperto sin embargo ni penso en eso, esta es una de las mayores funciones(escalabilidad del código) que yo le veo a la herencia, entre otras mas... que si me pongo a contar como ves me engancho y no termino...
En cambio tu de una clase ProductoRefrigeradoOCongelado, es o blanco o negro, la herencia pues como didáctica si, aunque como habrás sacado también del cuento, todo depende de quien lo coja, como lo quiera enfocar, y lo que pretenda hacer.
Yo por ejemplo si tengo 2 clases que tienen en común 20 atributos y 7 métodos... pues esta claro que voy a crear una clase padre para las dos...
Sobre tu código, bueno lo de las fechas tienes razón, estaban mal, pero vamos te aseguro que las fechas fue algo que es que ni miré XDD Bien visto!
Eso si en el método main del TestHerencia me encontrado algo raro:
while(copia.hasNext())
{
switch(i)
{
case 1: tipoDeProd = "Producto fresco"; break;
case 2: tipoDeProd = "Producto fresco"; break;
case 3: tipoDeProd = "Producto refrigerado"; break;
case 4: tipoDeProd = "Producto refrigerado"; break;
case 5: tipoDeProd = "Producto refrigerado"; break;
case 6: tipoDeProd = "Producto congelado por agua"; break;
case 7: tipoDeProd = "Producto congelado por agua"; break;
case 8: tipoDeProd = "Producto congelado por aire"; break;
case 9: tipoDeProd = "Producto congelado por aire"; break;
case 10: tipoDeProd = "Producto congelado por nitrogeno"; break;
default: tipoDeProd = tipoDeProd; break;
}
System.out.println("____________________________________________");
System.out.println("\n" + i++ + ": " + tipoDeProd );
System.out.println("____________________________________________");
//System.out.println("\n\t\t" + i++);
copia.next().verInfoDelProducto();
}
Ese while con ese switch tan repetitivo que duele a la vista... y si tuvieras 3.000.000 de productos en la lista?? XDDDD
Mira te paso una alternativa con el operador "instanceof", no es muy complicado, échale el ojo y si no entiendes algo ya nos comentas.
while(copia.hasNext()){
Producto aux=copia.next();
if(aux instanceof ProdFresco ){
tipoDeProd = "Producto fresco";
}
else if(aux instanceof ProdRefrigerado){
tipoDeProd = "Producto refrigerado";
}
else if(aux instanceof PCongeladoPorAgua){
tipoDeProd = "Producto congelado por agua";
}
else if(aux instanceof PCongeladoPorAire ){
tipoDeProd = "Producto congelado por aire";
}
else if(aux instanceof PCongeladoPorNitrogeno ){
tipoDeProd = "Producto congelado por nitrogeno";
}
System.out.println("____________________________________________");
System.out.println("\n" + i++ + ": " + tipoDeProd );
System.out.println("____________________________________________");
//System.out.println("\n\t\t" + i++);
aux.verInfoDelProducto();
}
Y nada, pos a seguir para adelante.
Un saludo!