Los patrones de diseño son estrategias reutilizables y probadas que resuelven problemas habituales en desarrollo de software. No son clases ni librerías, sino moldes para organizar el código y facilitar la mantenibilidad y evolución de los proyectos.
- Patrones creacionales: Mecanismos para la creación de objetos, mejorando la flexibilidad y la reutilización.
- Patrones estructurales: Indican cómo unir objetos y clases en estructuras amplias, manteniendo eficiencia y flexibilidad.
- Patrones de comportamiento: Gestionan la comunicación efectiva y la asignación de responsabilidades entre objetos.
Se centran en cómo se crean las instancias de objetos para garantizar control, flexibilidad y reutilización.
Propósito: Permite que una clase tenga solo una instancia y provee acceso global a ella.
Casos de uso:
- Gestores de conexión a base de datos
- Gestión de parámetros de configuración
- Logs y cachés
Paso a paso:
- Añade un campo estático privado a la clase para la instancia Singleton
private static DeathNote deathNote;
- Define un método estático público para obtener la instancia
public static DeathNote getInstance(String owner){ if (deathNote == null) { deathNote = new DeathNote(owner); } return deathNote; }
- Inicializa la instancia dentro del método estático
- Si por primera vez Light Yagami accede al Death Note, se crea la libreta y se le asigna como dueño
- Declara el constructor como privado
private DeathNote(String owner){ this.owner = owner; }
- Utiliza el método estático en tu código cliente
Ambos acceden a la misma instancia de la libreta
DeathNote lightLibreta = DeathNote.getInstance("Light Yagami"); DeathNote misaLibreta = DeathNote.getInstance("Misa Amane"); System.out.println(lightLibreta.owner); // "Light Yagami" System.out.println(misaLibreta.owner); // "Light Yagami"
Propósito: Define una interfaz para crear un objeto, dejando que las subclases decidan qué clase instanciar.
Elementos:
- Producto (Interfaz común)
- Productos concretos (Implementaciones)
- Creador (Clase abstracta/interfaz con método de fábrica)
- Creador concreto (Subclases que devuelven la instancia correcta)
Paso a paso:
- Define una interfaz para los productos
public interface Investigador { void investigarCaso(String caso); }
- Implementa las clases concretas
public class L implements Investigador { public void investigarCaso(String caso){ System.out.println("L investiga: " + caso); } } public class Near implements Investigador { public void investigarCaso(String caso){ System.out.println("Near investiga: " + caso); } }
- Crea la clase abstracta de la fábrica
public abstract class EquipoInvestigacion { public abstract Investigador crearInvestigador(); public void asignarCaso(String caso){ Investigador investigador = crearInvestigador(); investigador.investigarCaso(caso); } }
- Implementa las fábricas concretas
Así se pueden crear distintos equipos según el líder
public class EquipoL extends EquipoInvestigacion { public Investigador crearInvestigador(){ return new L(); } } public class EquipoNear extends EquipoInvestigacion { public Investigador crearInvestigador(){ return new Near(); } }
Gestionan cómo los objetos interactúan y asignan responsabilidades para facilitar el mantenimiento y la evolución.
Propósito: Permite elegir entre distintos algoritmos en tiempo de ejecución mediante el uso de interfaces y clases concretas.
Elementos:
- Interfaz de estrategia
- Estrategias concretas (implementaciones)
- Contexto que almacena la referencia y permite cambiar la estrategia
Paso a paso:
- Declara la interfaz de estrategia
public interface Plan { String ejecutarPlan(String objetivo); }
- Crea clases concretas para cada algoritmo
public class PlanLight implements Plan { public String ejecutarPlan(String objetivo){ return "Escribir el nombre de " + objetivo + " en la Death Note"; } } public class PlanL implements Plan { public String ejecutarPlan(String objetivo){ return "Colocar cámaras ocultas para descubrir a " + objetivo; } }
- Añade un campo en el contexto para almacenar la estrategia
public class Tactica { private Plan plan; public Tactica(Plan plan){ this.plan = plan; } public void cambiarPlan(Plan nuevoPlan){ this.plan = nuevoPlan; } public void ejecutar(String objetivo){ System.out.println(plan.ejecutarPlan(objetivo)); } }
- Proporciona un método para cambiar la estrategia
tactica.cambiarPlan(new PlanL());
- Utiliza la estrategia en los métodos del contexto
Tactica tacticaLight = new Tactica(new PlanLight()); tacticaLight.ejecutar("L"); // Escribir el nombre de L en la Death Note tacticaLight.cambiarPlan(new PlanL()); tacticaLight.ejecutar("Light"); // Colocar cámaras ocultas para descubrir a Light
Propósito: Define una dependencia uno-a-muchos, donde los observadores reciben notificaciones automáticas de cambios en el objeto observado.
Elementos:
- Sujeto (objeto observado)
- Observador (interfaz con método de actualización)
- Sujeto concreto (con lógica de notificación)
- Observador concreto (qué hacer con la notificación)
Paso a paso:
- Declara la interfaz para los observadores
public interface ShinigamiObserver { void notificarCambio(String propietario, String evento); }
- Implementa observadores concretos
public class Ryuk implements ShinigamiObserver { public void notificarCambio(String propietario, String evento){ System.out.println("Ryuk observa: " + propietario + " ha realizado " + evento); } } public class Rem implements ShinigamiObserver { public void notificarCambio(String propietario, String evento){ System.out.println("Rem observa: " + propietario + " ha realizado " + evento); } }
- Implementa la clase sujeto con manejo de lista de observadores
import java.util.List; import java.util.ArrayList; public class DeathNoteLibreta { private List<ShinigamiObserver> shinigamis = new ArrayList<>(); private String owner; public DeathNoteLibreta(String owner){ this.owner = owner; } public void escribirNombre(String nombre){ System.out.println(owner + " escribió " + nombre + " en la Death Note"); notificar("Escribir nombre: " + nombre); } private void notificar(String evento){ for (ShinigamiObserver s : shinigamis){ s.notificarCambio(owner, evento); } } }
- Crea métodos para añadir y quitar observadores
public void agregarShinigami(ShinigamiObserver s){ shinigamis.add(s); } public void quitarShinigami(ShinigamiObserver s){ shinigamis.remove(s); }
- Notifica a todos los observadores cuando ocurra un evento
DeathNoteLibreta libreta = new DeathNoteLibreta("Light"); ShinigamiObserver ryuk = new Ryuk(); ShinigamiObserver rem = new Rem(); libreta.agregarShinigami(ryuk); libreta.agregarShinigami(rem); libreta.escribirNombre("L"); // Ryuk y Rem reciben la notificación
© README.md by Navyri.