Saltar a contenido

Semana 9 - Clases Abstractas, Métodos Abstractos e Interfaces en Java (POO)

Contexto

Imagina que estás desarrollando un sistema para gestionar alimentos típicos de Medellín, como la bandeja paisa, el mondongo y el postre de arequipe. El sistema debe permitir describir los alimentos, prepararlos y clasificarlos según si son platos principales o postres. Usaremos clases abstractas, métodos abstractos e interfaces para modelar este sistema de forma clara y modular.

Este ejemplo proporciona indicaciones para que implementes el código, sin mostrar la solución completa. El objetivo es que comprendas cómo usar estos conceptos de POO en un escenario simple y práctico.


Requisitos del Sistema

  1. Clase Abstracta Alimento:

    • Representa un alimento genérico con atributos comunes como nombre (String) y precio (double).
    • Debe incluir un método concreto para mostrar la información del alimento (por ejemplo, mostrarInformacion()).
    • Debe incluir un método abstracto preparar() que cada tipo de alimento implementará de forma específica.
  2. Interfaz Clasificable:

    • Define un método para clasificar el alimento, por ejemplo, clasificar(), que indica si es un plato principal o un postre.
  3. Clases Concretas:

    • BandejaPaisa: Un plato principal que extiende Alimento e implementa Clasificable.
    • Mondongo: Otro plato principal que extiende Alimento e implementa Clasificable.
    • Arequipe: Un postre que solo implementa Clasificable (no extiende Alimento, para mostrar que las interfaces pueden usarse sin herencia).
  4. Clase Principal:

    • Debe demostrar el uso de polimorfismo creando instancias de los alimentos y llamando a sus métodos a través de referencias de tipo Alimento y Clasificable.

Indicaciones para la Implementación

1. Crear la Clase Abstracta Alimento

  • Declara la clase con la palabra clave abstract.
  • Define dos atributos: nombre (String) y precio (double).
  • Crea un constructor que inicialice estos atributos.
  • Implementa un método concreto mostrarInformacion() que imprima el nombre y precio del alimento.
  • Declara un método abstracto preparar() sin implementación (termina con ;).

Indicación:

abstract class Alimento {
    // Atributos
    // Constructor
    // Método concreto: mostrarInformacion()
    // Método abstracto: preparar()
}

2. Crear la Interfaz Clasificable

  • Declara una interfaz con la palabra clave interface.
  • Define un método abstracto clasificar() que no tenga implementación.
  • Opcionalmente, añade un método default llamado anunciar() que imprima un mensaje genérico como "¡Disfruta de la comida paisa!".

Indicación:

interface Clasificable {
    // Método abstracto: clasificar()
    // Método default: anunciar() (opcional)
}

3. Crear la Clase BandejaPaisa

  • Extiende la clase Alimento usando extends.
  • Implementa la interfaz Clasificable usando implements.
  • Crea un constructor que pase los parámetros nombre y precio al constructor de Alimento.
  • Implementa el método preparar() para describir cómo se prepara una bandeja paisa (por ejemplo, "Preparando bandeja paisa con chicharrón, frijoles y arroz").
  • Implementa el método clasificar() para indicar que es un plato principal.

Indicación:

class BandejaPaisa extends Alimento implements Clasificable {
    // Constructor
    // Implementar preparar()
    // Implementar clasificar()
}

4. Crear la Clase Mondongo

  • Similar a BandejaPaisa, extiende Alimento e implementa Clasificable.
  • En preparar(), describe la preparación del mondongo (por ejemplo, "Cocinando mondongo con callos y verduras").
  • En clasificar(), indica que es un plato principal.

Indicación:

class Mondongo extends Alimento implements Clasificable {
    // Constructor
    // Implementar preparar()
    // Implementar clasificar()
}

5. Crear la Clase Arequipe

  • Solo implementa Clasificable (no extiende Alimento para mostrar la flexibilidad de las interfaces).
  • Define un atributo propio, como tipo (String, por ejemplo, "postre de leche").
  • Implementa clasificar() para indicar que es un postre.

Indicación:

class Arequipe implements Clasificable {
    // Atributo tipo
    // Constructor
    // Implementar clasificar()
}

6. Crear la Clase Principal

  • Crea una clase Main con un método main.
  • Instancia un objeto de BandejaPaisa, uno de Mondongo y uno de Arequipe.
  • Usa un arreglo de tipo Alimento para almacenar BandejaPaisa y Mondongo, y llama a mostrarInformacion() y preparar() para demostrar polimorfismo.
  • Usa un arreglo de tipo Clasificable para almacenar los tres objetos y llama a clasificar() (y anunciar() si usaste un método default).
  • Opcionalmente, usa instanceof y casting para acceder a un método específico de BandejaPaisa.

Indicación:

public class Main {
    public static void main(String[] args) {
        // Crear instancias
        // Arreglo de Alimento para polimorfismo
        // Arreglo de Clasificable para polimorfismo
        // Opcional: usar instanceof y casting
    }
}


Objetivos Educativos

  • Clase Abstracta: Entender cómo Alimento proporciona una base común con atributos y métodos compartidos, y cómo preparar() fuerza a las clases hijas a definir su propia lógica.
  • Interfaz: Comprender que Clasificable permite que clases no relacionadas (como Arequipe) compartan un comportamiento común.
  • Polimorfismo: Ver cómo se pueden usar referencias de tipo Alimento y Clasificable para tratar objetos de manera uniforme.
  • Métodos Abstractos: Reconocer que preparar() y clasificar() obligan a las clases concretas a proporcionar implementaciones específicas.
  • Método default (opcional): Explorar cómo una interfaz puede incluir lógica compartida.

Solución

// Interfaz Clasificable: Define un comportamiento para clasificar alimentos
interface Clasificable {
    // Método abstracto para clasificar el alimento
    void clasificar();

    // Método default para anunciar el alimento
    default void anunciar() {
        System.out.println("¡Disfruta de la comida paisa!");
    }
}

// Clase abstracta Alimento: Base para los alimentos típicos
abstract class Alimento {
    protected String nombre;
    protected double precio;

    // Constructor
    public Alimento(String nombre, double precio) {
        this.nombre = nombre;
        this.precio = precio;
    }

    // Método concreto para mostrar información
    public void mostrarInformacion() {
        System.out.println("Alimento: " + nombre + ", Precio: $" + precio);
    }

    // Método abstracto para preparar el alimento
    public abstract void preparar();
}

// Clase BandejaPaisa: Extiende Alimento e implementa Clasificable
class BandejaPaisa extends Alimento implements Clasificable {
    public BandejaPaisa(String nombre, double precio) {
        super(nombre, precio);
    }

    @Override
    public void preparar() {
        System.out.println("Preparando " + nombre + " con chicharrón, frijoles, arroz y aguacate.");
    }

    @Override
    public void clasificar() {
        System.out.println(nombre + " es un plato principal.");
    }
}

// Clase Mondongo: Extiende Alimento e implementa Clasificable
class Mondongo extends Alimento implements Clasificable {
    public Mondongo(String nombre, double precio) {
        super(nombre, precio);
    }

    @Override
    public void preparar() {
        System.out.println("Cocinando " + nombre + " con callos, verduras y especias.");
    }

    @Override
    public void clasificar() {
        System.out.println(nombre + " es un plato principal.");
    }
}

// Clase Arequipe: Solo implementa Clasificable
class Arequipe implements Clasificable {
    private String tipo;

    public Arequipe(String tipo) {
        this.tipo = tipo;
    }

    @Override
    public void clasificar() {
        System.out.println("Arequipe (" + tipo + ") es un postre.");
    }
}

// Clase principal para demostrar el uso
public class Main {
    public static void main(String[] args) {
         // Crear instancias de los alimentos
        Alimento bandeja = new BandejaPaisa("Bandeja Paisa", 35000.0);
        Alimento mondongo = new Mondongo("Mondongo Antioqueño", 25000.0);
        Clasificable arequipe = new Arequipe("postre de leche");

        // Demostrar polimorfismo con clase abstracta Alimento
        System.out.println("=== Información y Preparación de Alimentos ===");
        Alimento[] alimentos = {bandeja, mondongo};
        for (Alimento alimento : alimentos) {
            alimento.mostrarInformacion();
            alimento.preparar();
        }

        // Demostrar polimorfismo con interfaz Clasificable
        System.out.println("\n=== Clasificación de Alimentos ===");
        Clasificable[] clasificables = {(Clasificable) bandeja, (Clasificable) mondongo, arequipe};
        for (Clasificable clasificable : clasificables) {
            clasificable.anunciar();
            clasificable.clasificar();
        }

    }
}