Programación Orientada a Objetos Avanzada en Java
En esta sección exploraremos conceptos avanzados de la Programación Orientada a Objetos (POO) en Java, como herencia múltiple mediante interfaces, clases internas, genéricos y el uso de patrones de diseño básicos.
Herencia Múltiple con Interfaces
Java no permite herencia múltiple con clases, pero puedes lograrlo utilizando interfaces. Una clase puede implementar múltiples interfaces.
Ejemplo:
public interface Volador {
void volar();
}
public interface Nadador {
void nadar();
}
public class Pato implements Volador, Nadador {
@Override
public void volar() {
System.out.println("El pato está volando.");
}
@Override
public void nadar() {
System.out.println("El pato está nadando.");
}
}
public class Main {
public static void main(String[] args) {
Pato pato = new Pato();
pato.volar();
pato.nadar();
}
}Clases Internas
Una clase interna es una clase definida dentro de otra clase. Estas permiten organizar mejor el código y encapsular funcionalidades relacionadas.
Tipos de Clases Internas
- Clases Internas Miembro:
public class Externa {
class Interna {
void mostrar() {
System.out.println("Soy una clase interna.");
}
}
public static void main(String[] args) {
Externa externa = new Externa();
Externa.Interna interna = externa.new Interna();
interna.mostrar();
}
}- Clases Anónimas:
public class Main {
public static void main(String[] args) {
Runnable tarea = new Runnable() {
@Override
public void run() {
System.out.println("Clase anónima ejecutada.");
}
};
tarea.run();
}
}Genéricos
Los genéricos permiten escribir clases y métodos que pueden manejar cualquier tipo de datos, proporcionando mayor flexibilidad y seguridad en tiempo de compilación.
Ejemplo: Clase Genérica
public class Caja<T> {
private T contenido;
public void guardar(T contenido) {
this.contenido = contenido;
}
public T obtener() {
return contenido;
}
public static void main(String[] args) {
Caja<String> caja = new Caja<>();
caja.guardar("Hola, mundo");
System.out.println(caja.obtener());
}
}Ejemplo: Método Genérico
public class Util {
public static <T> void imprimirArray(T[] array) {
for (T elemento : array) {
System.out.println(elemento);
}
}
public static void main(String[] args) {
Integer[] numeros = {1, 2, 3};
Util.imprimirArray(numeros);
}
}Patrones de Diseño Básicos
Los patrones de diseño son soluciones probadas para problemas comunes en el desarrollo de software. A continuación, se presentan dos patrones básicos: Singleton y Factory.
Singleton
El patrón Singleton garantiza que una clase tenga una única instancia y proporciona un punto de acceso global a esta.
public class Singleton {
private static Singleton instancia;
private Singleton() {}
public static Singleton getInstancia() {
if (instancia == null) {
instancia = new Singleton();
}
return instancia;
}
public void mostrarMensaje() {
System.out.println("Singleton ejecutado.");
}
}
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.getInstancia();
singleton.mostrarMensaje();
}
}Factory
El patrón Factory proporciona un método para crear objetos sin especificar la clase concreta.
public interface Producto {
void usar();
}
public class ProductoA implements Producto {
@Override
public void usar() {
System.out.println("Usando Producto A.");
}
}
public class ProductoB implements Producto {
@Override
public void usar() {
System.out.println("Usando Producto B.");
}
}
public class Fabrica {
public static Producto crearProducto(String tipo) {
if (tipo.equals("A")) {
return new ProductoA();
} else if (tipo.equals("B")) {
return new ProductoB();
}
return null;
}
}
public class Main {
public static void main(String[] args) {
Producto producto = Fabrica.crearProducto("A");
producto.usar();
}
}Buenas Prácticas en POO Avanzada
- Organización: Utiliza clases internas solo si son necesarias para encapsular funcionalidad.
- Flexibilidad: Usa genéricos para aumentar la reutilización del código y evitar errores de tipo.
- Diseño claro: Implementa patrones de diseño donde sean relevantes, evitando complejidad innecesaria.
- Documentación: Documenta adecuadamente las relaciones entre clases y patrones utilizados.
Conclusión
La programación orientada a objetos avanzada en Java amplía las capacidades básicas de la POO, permitiendo soluciones más flexibles, reutilizables y organizadas para problemas complejos. Dominar estos conceptos es clave para diseñar aplicaciones robustas y escalables.
