Semana 8 - Clases Abstractas en Java
Las clases abstractas en Java son una herramienta poderosa para la programación orientada a objetos, que permite definir la estructura y el comportamiento general de una clase sin tener que implementar todos sus métodos.
¿Qué son las clases abstractas?
- Plantillas incompletas: Las clases abstractas actúan como plantillas incompletas para otras clases. No se pueden instanciar directamente (crear objetos de ellas), pero sirven como base para clases concretas que las heredan y completan su implementación.
- Métodos abstractos: Una clase abstracta puede contener métodos abstractos, que se declaran pero no se implementan. La responsabilidad de implementar estos métodos recae en las clases que heredan de la clase abstracta.
- Definición de comportamiento general: Las clases abstractas definen un comportamiento general para un tipo de objeto, dejando la implementación específica a las clases derivadas.
- Abstracción: El concepto de clase abstracta promueve la abstracción, ocultando la complejidad de la implementación y mostrando únicamente la interfaz necesaria.
Ejemplo:
Imaginemos que estamos creando un sistema de gestión de vehículos. Podemos definir una clase abstracta llamada "Vehiculo":
public abstract class Vehiculo {
private String marca;
private String modelo;
public Vehiculo(String marca, String modelo) {
this.marca = marca;
this.modelo = modelo;
}
public String getMarca() {
return marca;
}
public String getModelo() {
return modelo;
}
// Método abstracto que define el comportamiento de moverse
public abstract void moverse();
}
En este ejemplo:
Vehiculo
es una clase abstracta, definida con la palabra claveabstract
.- Tiene atributos privados para
marca
ymodelo
, y un constructor para inicializarlos. - También tiene métodos para obtener la marca y el modelo del vehículo.
- El método
moverse()
es abstracto, ya que solo se declara (conabstract
) pero no se implementa.
¿Cómo se utilizan las clases abstractas?
- Herencia: Las clases concretas heredan de la clase abstracta.
- Implementación de métodos abstractos: Las clases derivadas deben implementar todos los métodos abstractos de la clase padre.
- Especialización del comportamiento: Cada clase derivada puede especializar el comportamiento definido en la clase abstracta.
Ejemplo de herencia:
public class Coche extends Vehiculo {
public Coche(String marca, String modelo) {
super(marca, modelo);
}
@Override
public void moverse() {
System.out.println("El coche se mueve sobre ruedas");
}
}
public class Avion extends Vehiculo {
public Avion(String marca, String modelo) {
super(marca, modelo);
}
@Override
public void moverse() {
System.out.println("El avión se mueve en el aire");
}
}
En este ejemplo:
Coche
yAvion
son clases concretas que heredan de la clase abstractaVehiculo
.- Ambas clases implementan el método abstracto
moverse()
con su propia lógica específica.
Ventajas de las clases abstractas:
- Reutilización de código: Se reduce la duplicación de código al definir el comportamiento general en una sola clase abstracta.
- Abstracción: Se facilita la abstracción de conceptos, ocultando detalles de implementación.
- Polimorfismo: Permite crear diferentes tipos de objetos que comparten una misma interfaz (el método
moverse()
en este caso).
Métodos Abstractos en Java: La Base de la Abstracción
Los métodos abstractos son la pieza clave de las clases abstractas en Java. Son como promesas de comportamiento que se declaran, pero no se implementan. La responsabilidad de definir la lógica de estos métodos recae en las clases que heredan de la clase abstracta.
Características de los métodos abstractos:
- Solo declaración: Los métodos abstractos solo se declaran, usando la palabra clave
abstract
antes de la declaración del método. - No tienen cuerpo: Los métodos abstractos no tienen cuerpo de código entre llaves (
{}
). - Deben ser implementados: Las clases derivadas (hijas) que heredan de la clase abstracta deben implementar todos los métodos abstractos.
- Implementación específica: La implementación del método abstracto puede variar entre las clases derivadas, lo que permite especializar el comportamiento.
Ejemplo:
public abstract class Animal {
// Método abstracto para definir el sonido que emite un animal
public abstract void hacerSonido();
// Otros métodos pueden ser concretos
public void comer() {
System.out.println("El animal está comiendo");
}
}
En este ejemplo:
hacerSonido()
es un método abstracto, solo declarado pero no implementado.- Las clases que hereden de
Animal
(comoPerro
oGato
) deberán implementarhacerSonido()
con su propio comportamiento específico. - El método
comer()
es concreto, ya que tiene un cuerpo definido.
Ventajas de los métodos abstractos:
- Abstracción: Permiten definir un comportamiento común sin necesidad de conocer la implementación exacta.
- Flexibilidad: La implementación del método abstracto puede variar entre las clases derivadas, lo que permite adaptarse a diferentes necesidades.
- Polimorfismo: Facilitan el polimorfismo, ya que las clases derivadas pueden responder de forma diferente al mismo método.
- Reutilización: Promueven la reutilización de código, al definir el comportamiento general en la clase abstracta.
Ejemplos de uso:
- Interfaces gráficas: Se pueden definir métodos abstractos para el comportamiento de botones, menus, etc. Cada tipo de botón o menu implementaría estos métodos de forma específica.
- Sistemas de gestión: Se pueden definir métodos abstractos para operaciones comunes en diferentes tipos de entidades (usuarios, productos, etc.).
- Diseño de patrones: Se pueden utilizar para implementar patrones como "Factory Method" o "Template Method".
Ejemplo de Clase Abstracta con Métodos Abstractos: Sistema de Transporte Público
Este ejemplo ilustra cómo usar clases abstractas y métodos abstractos para modelar un sistema de transporte público en Colombia, con énfasis en la diversidad de modalidades existentes.
Clase Abstracta:
public abstract class TransportePublico {
private String nombreCompania;
private String tipoTransporte;
public TransportePublico(String nombreCompania, String tipoTransporte) {
this.nombreCompania = nombreCompania;
this.tipoTransporte = tipoTransporte;
}
public String getNombreCompania() {
return nombreCompania;
}
public String getTipoTransporte() {
return tipoTransporte;
}
// Métodos abstractos:
public abstract double calcularTarifa(double distancia);
public abstract String getMedioPago();
public abstract String getRuta();
public abstract int getCapacidad();
// Método concreto:
public void mostrarInformacion() {
System.out.println("Nombre de la compañía: " + nombreCompania);
System.out.println("Tipo de transporte: " + tipoTransporte);
}
}
Explicación:
- La clase
TransportePublico
es abstracta, lo que indica que no se pueden crear instancias directas de ella. - Tiene atributos para el nombre de la compañía y el tipo de transporte (ej. "Bus", "Metro", "TransMilenio").
- Contiene métodos abstractos:
calcularTarifa(double distancia)
: calcula la tarifa de acuerdo a la distancia, pero la implementación es específica para cada tipo de transporte.getMedioPago()
: devuelve los medios de pago aceptados (ej. "Efectivo", "Tarjeta", "App").getRuta()
: devuelve la ruta que recorre el transporte (ej. "Estación A - Estación B").getCapacidad()
: devuelve la capacidad máxima de pasajeros.
- Tiene un método concreto
mostrarInformacion()
que muestra información general sobre el transporte.
Clases Derivadas:
// Clase para buses
public class Bus extends TransportePublico {
public Bus(String nombreCompania) {
super(nombreCompania, "Bus");
}
@Override
public double calcularTarifa(double distancia) {
// Lógica específica para calcular la tarifa de un bus
return 2000 + distancia * 100; // Ejemplo simple
}
@Override
public String getMedioPago() {
return "Efectivo, Tarjeta";
}
@Override
public String getRuta() {
// Implementación específica para la ruta del bus
return "Terminal - Centro";
}
@Override
public int getCapacidad() {
return 50; // Capacidad típica de un bus
}
}
// Clase para el Metro de Medellín
public class Metro extends TransportePublico {
public Metro(String nombreCompania) {
super(nombreCompania, "Metro");
}
@Override
public double calcularTarifa(double distancia) {
// Lógica específica para calcular la tarifa del metro
return 2500; // Tarifa fija en el Metro de Medellín
}
@Override
public String getMedioPago() {
return "Tarjeta Cívica";
}
@Override
public String getRuta() {
// Implementación específica para la ruta del metro
return "Estación A - Estación Z";
}
@Override
public int getCapacidad() {
return 100; // Capacidad típica de un tren de metro
}
}
Explicación:
- Se crean clases derivadas específicas para "Bus" y "Metro".
- Cada clase implementa los métodos abstractos de
TransportePublico
con la lógica específica para ese tipo de transporte.
Uso del Ejemplo:
public class EjemploTransporte {
public static void main(String[] args) {
// Crear un objeto Bus
Bus bus = new Bus("Transmilenio");
bus.mostrarInformacion();
System.out.println("Tarifa: " + bus.calcularTarifa(10));
// Crear un objeto Metro
Metro metro = new Metro("Metro de Medellín");
metro.mostrarInformacion();
System.out.println("Tarifa: " + metro.calcularTarifa(5));
}
}
Beneficios de esta implementación:
- Abstracción: La clase
TransportePublico
define el comportamiento general de un sistema de transporte público, sin preocuparse por detalles específicos de cada tipo de transporte. - Flexibilidad: Se pueden añadir nuevos tipos de transporte (ej. "Tranvía", "Cable Aéreo") simplemente creando nuevas clases derivadas de
TransportePublico
. - Reutilización de código: El código común se define en la clase abstracta, evitando la duplicación en las clases derivadas.
Actividad: Simulando un Sistema de Gestión de Mascotas
Objetivo: Implementar un sistema de gestión de mascotas en Java utilizando clases abstractas y métodos abstractos.
Descripción:
El sistema de gestión de mascotas debe incluir:
- Clase Abstracta
Mascota
:- Atributos: nombre, especie, raza, edad, tamaño, color, estado de salud.
- Métodos abstractos:
hacerSonido()
: Emita el sonido característico de la mascota.alimentar()
: Describe cómo se alimenta la mascota.cuidar()
: Describe cómo se cuida la mascota (bañarse, cepillarse, etc.).
- Método concreto:
mostrarInformacion()
: Muestra información general de la mascota.
- Clases Concretas:
Perro
Gato
Pajaro
Tortuga
Pistas y Guías:
Paso 1: Definición de la Clase Abstracta Mascota
- Crea un paquete:
com.mascotas.gestion
- Define la clase
Mascota
:- Declara los atributos (nombre, especie, raza, edad, tamaño, color, estado de salud).
- Crea el constructor para inicializar los atributos.
- Define los métodos
getNombre()
,getEspecie()
,getRaza()
,getEdad()
,getTamaño()
,getColor()
,getEstadoSalud()
. - Declara los métodos abstractos
hacerSonido()
,alimentar()
,cuidar()
. - Define el método concreto
mostrarInformacion()
.
Paso 2: Creación de Clases Concretas
- Crea las clases:
Perro
,Gato
,Pajaro
,Tortuga
. - Extiende cada clase de
Mascota
:public class Perro extends Mascota { ... }
- Implementa los métodos abstractos en cada clase:
hacerSonido()
: Define el sonido que emite la mascota (ladrar, maullar, cantar, etc.).alimentar()
: Describe la forma de alimentar a la mascota (croquetas, alimento balanceado, frutas, etc.).cuidar()
: Describe cómo se cuida a la mascota (paseos, baño, cepillado, etc.).
Paso 3: Clase Principal Main.java
- Crea la clase
Main
en el paquetecom.mascotas.gestion
: - Crea objetos de cada tipo de mascota:
- Ejemplo:
Perro perro = new Perro("Max", "Canino", "Labrador", 3, "Mediano", "Dorado", "Saludable");
- Ejemplo:
- Prueba las funcionalidades:
- Llama a los métodos
hacerSonido()
,alimentar()
,cuidar()
,mostrarInformacion()
.
- Llama a los métodos
- Imprime los resultados en la consola.
Ejemplo de código:
// com.mascotas.gestion.Mascota.java
package com.mascotas.gestion;
public abstract class Mascota {
// ... (Atributos, Constructor, Métodos)
}
// com.mascotas.gestion.Perro.java
package com.mascotas.gestion;
public class Perro extends Mascota {
// ... (Constructor, Implementación de Métodos Abstractos)
}
// com.mascotas.gestion.Main.java
package com.mascotas.gestion;
public class Main {
public static void main(String[] args) {
// ... (Creación de objetos y pruebas)
}
}
Entrega:
- Sube tu código al repositorio de GitHub.
- Comparte el enlace de tu repositorio de GitHub en el archivo de evidencias de tu carpeta compartida en la semana correspondiente.