Autor Tema: Ejercicio esquema reflejando relaciones de herencia entre clases Java (CU00687B)  (Leído 7084 veces)

Dan_SB

  • Avanzado
  • ****
  • Mensajes: 273
  • *<DanielsCK>*
    • Ver Perfil
Buenas noches

Vengo aquí dudoso con una pregunta sobre este ejercicio, hay algo que no capto del enunciado y decidi realizar algo... les presento mi esquema:


Explicando el esquema: Vamos por clase. primero hablemos de la super clase Producto.

En mi esquema tengo en la super clase Producto 4 atributos que son fecha de caducidad, numero de lote, fecha de envasado y pais de origen. Estos dos ultimos los agrege por la razón de que si lees el enunciado bien, puedes notar que en todas las clases piden esto: fecha de envasado y pais de origen. Nos ahorrariamos de escribir en cada clase setFechaEnvasado... setPaisOrigen... getFechaEnvasado... etc...

Con la clase ProductoFresco, como solo requiere de fecha de envasado y pais de origen, tan solo va a heredar de la super clase Producto y punto... al no tener atributos propios que lo identifiquen.

Viene el meollo. Modifique un poco el esquema... reemplaze la clase ProductoFrio por la clase ProductoCongelado.. Explico porque:

Si comparamos los atributos de ProductoRefrigerado y ProductoCongelado
vamos a encontrar una característica similar... se trata de temperatura recomendada. Pense en convertir a ProductoRefrigerado como una super clase, pero no tendria sentido.

Citar
Los productos refrigerados deben llevar el código del organismo de supervisión alimentaria, la fecha de envasado, la temperatura de mantenimiento recomendada y el país de origen. Los productos congelados deben llevar la fecha de envasado, el país de origen y la temperatura de mantenimiento recomendada.

ProductoRefrigerado tiene al parecer una característica especifica que es el código de organismo de supervision alimentaria.... si ProductoRefrigerado se vuelve en una super clase intermedia, ProductoCongelado va a heredar la caracteristica especifica de ProductoRefrigerado... y por eso, cree esta clase ProductoFrio.

¿Porque elimine la clase ProductoCongelado?
Pues, esta clase se convertiría en el mismo caso que ProductoFresco al carecer de una característica especifica... perooo... no elimine tal clase ProductoFresco por no tener subclases o "hijos".
Con ProductoCongelado, ya es otra historia, se volveria una clase demas y repetida. Pensemos... ¿Que heredarian las subclases CongeladoAire, CongeladoNitrogeno y CongeladoAgua de la clase ProductoCongelado? nada. ProductoClase tendria como atributos fecha de envasado y pais de origen... cosa que ya todas las clases estan heredando de la super clase Producto.

Que opinan de esto chicos??? estare esperando sus correcciones y comentarios. Y si fuese el caso de que no exista ningun problema con este diagrama, inmediatamente prosigo con la codificacion!

Hice esto en paint, lo mejor que pude... D;
Saludos!
« Última modificación: 18 de Abril 2015, 22:39 por Alex Rodríguez »
"Luchar por tus sueños y cumplirlos... eso es vivir.."

toni_apr

  • Avanzado
  • ****
  • Mensajes: 497
  • Curiosidad, es uno de los pilares del Conocimiento
    • Ver Perfil
Re:Ejercicio (CU00687B), dudas sobre el enunciado
« Respuesta #1 en: 18 de Abril 2015, 17:16 »
Hola Dan

No sé si has empezado la codificación como dices al final. Aprovecho para hacer mis comentarios a tu esquema/diagrama.

Respecto a tu esquema.
En tu mensaje das razones para hacer tus cambios
1º ProductoFresco no tiene atributos porque los hereda todos de Producto.
Tiene su lógica, viendo los nombres, si, ProductoFresco es un nivel inferior a Producto. Pero en el enunciado no se pide crear la clase Producto.
Yo creo que si a tu clase Producto le cambias el nombre por ProductoFresco y eleminas la clase sin parámetros, tu estructura de clases se mantiene.
Este cambio hará que el resto del productos hereden de ProductoFresco (cosa que no sucede en el mundo real). Pero yo pienso que mientras nuestro proyecto discrimine cada objeto de los demás tendrá una estructura consistente.
Nuestra relación de herencia se basa en los atributos compartidos, no en el nombre que damos a las clases. Tal como interpreto yo en esta parte del enunciado
Citar
b) Crear superclases intermedias (aunque no se correspondan con la descripción dada de la empresa) para agrupar atributos y métodos cuando sea posible. Esto corresponde a "realizar abstracciones" en el ámbito de la programación, que pueden o no corresponderse con el mundo real.

2º Y siguiendo la premisa anterior yo conservaría a la clase ProductoRefrigerado subclase de ProductoCongelado (atendiéndome siempre a los atributos compartidos)

Lo anterior es opinión mía, la herencia la deciden los atributos no la vida real.

Saludos

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2053
    • Ver Perfil
Hola, mi recomendación: un esquema de herencia no debe contradecir el mundo real, a lo sumo, puede crear artefactos o clases intermedias que faciliten la labor del programador, pero sin ir en contra de los conceptos del mundo real. Lo que tratamos de hacer al crear un diseño de clases Java es en buena medida conceptualizar el mundo real.

Una cuestión que se debe tener presente al crear un programa es la posibilidad de ampliación. Como programadores, tenemos que intentar crear diseños consistentes, y la consistencia viene dada por varios factores. Uno de ellos es que el diseño prevea posibles ampliaciones del programa. Por ello lo lógico es tener una superclase Producto, de la que hereden los distintos tipos de productos. Hacer que ProductoCongelado herede de ProductoFresco no reflejaría el mundo real y generaría problemas cuando hubiera que ampliar el programa. Los programas rara vez son algo terminado, algo final, un programa a nivel profesional siempre requiere cambios y mantenimiento. Otro motivo para no contradecir el mundo real es pensar que cuando como programadores terminamos un programa, es posible que el mantenimiento de ese programa tenga que realizarlo otra persona. Si el diseño no es autoexplicativo, si hemos deformado la realidad, la persona que vaya a mantener ese programa tendrá problemas para entenderlo y esto generará sobrecostes en el mantenimiento del programa.

El diseño planteado en este hilo es el que me parece más correcto: www.aprenderaprogramar.com/foros/index.php?topic=2342

Saludos

Dan_SB

  • Avanzado
  • ****
  • Mensajes: 273
  • *<DanielsCK>*
    • Ver Perfil
Hola!

Eso mismo quise hacer, algo que vaya con el mundo real. Si tecleas en google "Productos fríos" vas a ver helados, bebidas frías, productos congelados como carnes, hielo, y paletas... es por eso que decidí crear esa clase y llamarla ProductoFrio, porque abarca Productos Refrigerados y Congelados. Para saber si el producto es refrigerado o congelado, pienso que se le podría poner una condición al agregar la temperatura y que la clase diga si es congelado o no.

Lo que aun no entiendo, es que cosa van a heredar las clases Congelado por aire, nitrógeno y agua, si los atributos de producto congelado son fecha de envasado, el país de origen y la temperatura recomendada... la herencia según vi, es ahorrarte código (por decirlo así). No estaríamos creando una clase demas con las mismas cosas ? De la super clase ya se esta heredando fecha de envasado y el pais de origen. Y temperatura recomendada de la clase intermedia que metí..

Tengo la idea en la cabeza, aun no empezado a codificar por cierto, hasta estar seguro si esta correcto o con su aprobación. Por mientras me entretenia con html :P
"Luchar por tus sueños y cumplirlos... eso es vivir.."

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2053
    • Ver Perfil
Hola Dan, lo que le faltaría a tu esquema es una clase ProductoCongelado, de donde hereden los distintos tipos de productos congelados. En la clase ProductoCongelado tendríamos todo lo común a los productos congelados. Si en el momento de crear el programa no tenemos nada común, quedará una clase vacía de contenido. Esto puede parecer poco recomendable (¿para qué tener una clase vacía?) pero es razonable en las siguientes situaciones:

- Es previsible que cuando el programa se desarrolle esa clase permita agrupar aspectos comunes de distintas subclases. Es decir, aunque ahora mismo no nos sea útil, prevemos que sea útil en un futuro próximo.

- Hace que el diseño refleje el mundo real. La falta de la clase dejaría "cojo" el diseño.

- Otras a considerar

Si en tu diseño incluyes la clase ProductoCongelado, ya tendrás el diseño preparado para cuando tengas que agrupar aspectos comunes de los productos congelados. Si no la incluyes, cuando en el futuro tuvieras que agrupar aspectos comunes de productos congelados tendrías que modificar el diseño, y una modificación de diseño es costosa porque puede tener más efectos colaterales.

Siempre habrá que hacer modificaciones de diseño, pero hay que crear diseños lo más consistentes posibles que eviten en la medida de lo posible modificaciones por situaciones que son más o menos previsibles.

Saludos.

Dan_SB

  • Avanzado
  • ****
  • Mensajes: 273
  • *<DanielsCK>*
    • Ver Perfil
Okay ale. gracias por su comentario, ya arreglo el esquema y programo ahorita!
"Luchar por tus sueños y cumplirlos... eso es vivir.."

Dan_SB

  • Avanzado
  • ****
  • Mensajes: 273
  • *<DanielsCK>*
    • Ver Perfil
Ok aquí voy con el código, disculpen la tardanza, es que en la U ya andamos haciendo exámenes finales del cuatrimestre xd

Producto:
Código: [Seleccionar]
ackage comidaHerencia;

public class Producto {
    String fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen;
   
    public Producto(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen){
        this.fechaCaducidad = fechaCaducidad;
        this.numeroLote = numeroLote;
        this.fechaEnvasado = fechaEnvasado;
        this.paisDeOrigen = paisDeOrigen;
    }
   
    public void setFechaCaducidad(String fecha){
        fechaCaducidad = fecha;
    }
   
    public void setNumeroLote(String num){
        numeroLote = num;
    }
   
    public void setFechaEnvasado(String fecha){
        fechaEnvasado = fecha;
    }
   
    public void setPaisDeOrigen(String pais){
        paisDeOrigen = pais;
    }
       
    public String getFechaCaducidad(){
        return fechaCaducidad;
    }
   
    public String getNumeroLote(){
        return numeroLote;
    }
   
    public String getFechaEnvasado(){
        return fechaEnvasado;
    }
   
    public String getPaisDeOrigen(){
        return paisDeOrigen;
    }
   
    public void imprimirInfo(){
        System.out.println("Fecha Caducidad: " + getFechaCaducidad() + "\nNumero de Lote: " + getNumeroLote() + "\nFecha de Envasado: " + getFechaEnvasado() + "\nPais de Origen: " + getPaisDeOrigen() + "\n");
    }
}

ProductoFresco:
Código: [Seleccionar]
package comidaHerencia;

public class ProductoFresco extends Producto {   
    public ProductoFresco(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen);
    }   
}

ProductoRefrigerado:
Código: [Seleccionar]
package comidaHerencia;

public class ProductoRefrigerado extends Producto{
    private String codigoSupervisionAlimentaria;
   
    public ProductoRefrigerado(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, String codigo){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen);
        codigoSupervisionAlimentaria = codigo;
    }
   
    public void setCodigoSupervisionAlimentaria(String codigo){
        codigoSupervisionAlimentaria = codigo;
    }
   
    public String getCodigoSupervisionAlimentaria(){
        return codigoSupervisionAlimentaria;
    }
   
    public void imprimirDatos(){
        System.out.println("Codigo de Supervision Alimentaria: " + getCodigoSupervisionAlimentaria());
        imprimirInfo();       
    }
}

ProductoFrio:
Código: [Seleccionar]
package comidaHerencia;

public class ProductoFrio extends Producto {
    private double tempCongelacionRecomendada;
   
    public ProductoFrio(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, double tempCongelacionRecomendada){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen);
        this.tempCongelacionRecomendada = tempCongelacionRecomendada;
    }
   
    public void setTemperaturaRecomendada(double temperatura){
        tempCongelacionRecomendada = temperatura;
    }
   
    public double getTemperaturaRecomendada(){
        return tempCongelacionRecomendada;
    }
   
    public void imprimirInformacion(){
        System.out.println("Temperatura Recomendada: " + getTemperaturaRecomendada());
        imprimirInfo();
    }
}

ProductoCongelado:
Código: [Seleccionar]
package comidaHerencia;

public class ProductoCongelado extends ProductoFrio {     
    public ProductoCongelado(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, double tempCongelacionRecomendada){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen, tempCongelacionRecomendada);
    }
}

CongeladoAgua:
Código: [Seleccionar]
package comidaHerencia;

public class CongeladoAgua extends ProductoCongelado {
    private double gramosSal, litrosAgua;
    public CongeladoAgua(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, double tempCongelacionRecomendada){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen, tempCongelacionRecomendada);
        gramosSal = 0; litrosAgua = 0;
    } 
    public void setSal(double sal){gramosSal = sal;}
    public void setLitrosAgua(double litro){litrosAgua = litro;}
    public double calcularSalinidad(){
        double salinidad = gramosSal * litrosAgua;
        return salinidad;
    }
    public double getSal(){return gramosSal;}
    public double getLitrosAgua(){return litrosAgua;}
   
    public void imprimirDatos(){
        System.out.println("Salinidad del agua: " + calcularSalinidad());
        imprimirInformacion();     
    }
}

CongeladoAire:
Código: [Seleccionar]
package comidaHerencia;

public class CongeladoAire extends ProductoCongelado{
    private double porNitrogeno, porOxigeno, porDioxCarbono, porVaporAgua;
    public CongeladoAire(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, double tempCongelacionRecomendada){
        super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen, tempCongelacionRecomendada);
        porNitrogeno = 0; porOxigeno = 0; porDioxCarbono = 0; porVaporAgua = 0;
    }   
   
    public void setPorNitrogeno(double num){porNitrogeno = num;}   
    public void setPorOxigeno(double num){porOxigeno = num;}   
    public void setPorDioxCarbono(double num){porDioxCarbono = num;}
    public void setPorVaporAgua(double num){porVaporAgua = num;}
    public double getPorNitrogeno(){return porNitrogeno;}
    public double getPorOxigeno(){return porOxigeno;}
    public double getPorDioxCarbono(){return porDioxCarbono;}
    public double getPorVaporAgua(){return porVaporAgua;}
   
    public void imprimirDatos(){
        System.out.println("Porcentaje de nitrogeno: " + getPorNitrogeno() + "%\nPorcentaje de oxigeno: " + getPorOxigeno() + "%\nPorcentaje de Dioxido de carbono: "
        + getPorDioxCarbono() + "%\nPorcentaje de vapor de agua: " + getPorVaporAgua());
        imprimirInformacion();       
    }
}

CongeladoNitrogeno:
Código: [Seleccionar]
package comidaHerencia;

public class CongeladoNitrogeno extends ProductoCongelado{
    private String metodoCongelacion;
    private String tiempoExposicion;
    public CongeladoNitrogeno(String fechaCaducidad, String numeroLote, String fechaEnvasado, String paisDeOrigen, double tempCongelacionRecomendada){
         super(fechaCaducidad, numeroLote, fechaEnvasado, paisDeOrigen, tempCongelacionRecomendada);
         metodoCongelacion = "Desconocido";
         tiempoExposicion = "";
    }
   
    public void setMetodoCongelacion(String metodo){metodoCongelacion = metodo;}
    public void setTiempoExposicion(String tiempo){tiempoExposicion = tiempo;}
    public String getMetodoCongelacion(){return metodoCongelacion;}
    public String getTiempoExposicion(){return tiempoExposicion;}
   
    public void imprimirDatos(){
        System.out.println("Metodo de congelacion: " + getMetodoCongelacion() + "\nTiempo de exposicion: " + getTiempoExposicion());
        imprimirInformacion();       
    }
}

testHerencia3:
Código: [Seleccionar]
package comidaHerencia;
import java.util.Scanner;

public class testHerencia3 {
    public static void main(String[]args){
        Scanner in = new Scanner(System.in); int elige = 0;
        ProductoFresco tomate = new ProductoFresco("30/04/2015","L1021015","20/04/2015","Panamá");
        ProductoFresco manzana = new ProductoFresco("03/05/2015","L1022015","20/04/2015","EEUU");
        ProductoRefrigerado leche = new ProductoRefrigerado("10/05/2015","L1118015","24/04/2015","España","C#12083");
        ProductoRefrigerado jugo = new ProductoRefrigerado("14/05/2015","L0912015","20/04/2015","Alemania","C#56785");
        ProductoRefrigerado queso = new ProductoRefrigerado("14/05/2015","L1112015","02/04/2015","Panamá","C#67890");
        CongeladoAgua pescado = new CongeladoAgua("14/7/2015","L2032015","10/04/2015","Panamá",-2.0);
        pescado.setLitrosAgua(5);
        pescado.setSal(283.5);
        CongeladoAgua cangrejo = new CongeladoAgua("15/8/2015","L1023015","11/04/2015","Panamá",-2.0);
        cangrejo.setLitrosAgua(3);
        cangrejo.setSal(170.1);
        CongeladoAgua rex = new CongeladoAgua("15/6/2015","L2012015","11/04/2015","Costa Rica",-1.8);
        rex.setLitrosAgua(5);
        rex.setSal(170.1);
        CongeladoAgua pulpo = new CongeladoAgua("15/6/2015","L2309015","16/05/2015","Colombia",-2.0);
        pulpo.setLitrosAgua(2);
        pulpo.setSal(113.4);
        CongeladoNitrogeno cordero = new CongeladoNitrogeno("20/6/2015","L2609015","20/05/2015","Argentina",-2.2);
        cordero.setMetodoCongelacion("Criogénica");
        cordero.setTiempoExposicion("6 meses");
        do{
        System.out.println("Ingrese 1 para visualizar la informacion de los productos frescos.\n"
                + "Ingrese 2 para visualizar la informacion de los productos refrigerados.\n"
                + "Ingrese 3 para visualizar la informacion de los productos congelados.\n"
                + "Ingrese 4 para salir.");
        elige = in.nextInt();
        switch(elige){
            case 1: System.out.println("Productos frescos:");
                tomate.imprimirInfo();
                manzana.imprimirInfo();
            break;
            case 2: System.out.println("Productos refrigerados:");
                leche.imprimirDatos();
                jugo.imprimirDatos();
                queso.imprimirDatos();
            break;
            case 3: System.out.println("PRODUCTOS CONGELADOS.\nCongelados por agua: ");
                pescado.imprimirDatos();
                cangrejo.imprimirDatos();
                rex.imprimirDatos();
                pulpo.imprimirDatos();
                System.out.println("Congelados por nitrogeno:");
                cordero.imprimirDatos();
            break;
            case 4: System.out.println("Prueba finalizada!"); break;
            default: System.out.println("Caracter invalido."); break;
        }
        }while(elige < 4);
    }
}

Ejecucion:




"Luchar por tus sueños y cumplirlos... eso es vivir.."

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2053
    • Ver Perfil
Hola Dan, buen código, has hecho hasta los cálculos de salinidad :)

Lo único que no veo bien resuelto es esto:

Código: [Seleccionar]
switch(elige){
            case 1: System.out.println("Productos frescos:");
                tomate.imprimirInfo();
                manzana.imprimirInfo();
            break;
            case 2: System.out.println("Productos refrigerados:");
                leche.imprimirDatos();
                jugo.imprimirDatos();
                queso.imprimirDatos();
            break;
            case 3: System.out.println("PRODUCTOS CONGELADOS.\nCongelados por agua: ");
                pescado.imprimirDatos();
                cangrejo.imprimirDatos();
                rex.imprimirDatos();
                pulpo.imprimirDatos();
                System.out.println("Congelados por nitrogeno:");
                cordero.imprimirDatos();
            break;
            case 4: System.out.println("Prueba finalizada!"); break;
            default: System.out.println("Caracter invalido."); break;
        }

Aunque sea un ejercicio, en general nunca recorreremos una colección a mano, sino usando alguna forma de recorrido automatizada (como un iterador, un bucle for, un bucle for extendido, etc.). Siempre hay que pensar que una colección en vez de 2 elementos podría tener 200 y no vamos a escribir 200 líneas pro1.imprimirInfo(), pro2.imprimirInfo(), pro3.imprimirInfo() ... hasta pro200.imprimirInfo(), por eso nunca recorremos las colecciones a mano, ni siquiera cuando tienen pocos elementos.

Saludos

Dan_SB

  • Avanzado
  • ****
  • Mensajes: 273
  • *<DanielsCK>*
    • Ver Perfil
A bueno, esta bien, la única consulta en ese caso seria y aprovechando que se toco este tema:

Cuando usas un for each, bucle for, iterador, etc, para recorrer una colección, se recorre todos los miembros de dicha colección... ahora, que pasa si yo quiero insertarle al programa la opción de elegir un integrante de la colección especifica para ver su informacion? Suponga que me dan un menú y quiero solo ver la información de tomate, que podría hacer? Creo que tengo la mente bloqueada en este punto, ya que por mas que piense solo se me ocurre de esta forma (con un switch o for), y no puede ser asi, ya que como dices, que pasaria si la coleccion tuviese 200 elementos? estaria eternamente escribiendo lo q pasaria en cada caso de los 200... 

Sera que me falta dar algo mas? o ya he visto lo suficiente para saber como hacerlo, solo que no se me ha "activado el cable" aun para resolverlo? ???
"Luchar por tus sueños y cumplirlos... eso es vivir.."

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2053
    • Ver Perfil
Hola Dan, suponte que estás recorriendo una colección de personas y quieres mostrar solo la información de las personas que se llamen Alberto.

El código sería como este:

Código: [Seleccionar]
for (int i=0; i<coleccionPersonas.size()-1; i++) {

if (coleccionPersonas.get(i).getName(i).equals("Alberto") {
    System.out.println("Hemos encontrado una persona que se llama Alberto. A continuacion sus datos:");
    coleccionPersonas.get(i).mostrarDatos(); //Extraemos el objeto en posición i
}

}


coleccionPersonas.get(i) recupera un objeto situado en la posición i dentro de la colección

Una vez tenemos el objeto podemos operar sobre él, si suponemos que ese objeto es un objeto Persona que tiene un método getName() recuperamos el nombre usando coleccionPersonas.get(i).getName(i)

Ese nombre lo podemos comparar con lo que buscamos.

Igual que nombre podríamos comparar otros atributos. En caso de que la comparación sea compleja (entre objetos) hay que usar equals según se explica en la entrega CU00694B del curso.

Saludos

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".