Cadena de Responsabilidad
Este patrón facilita la delegaicón de solicitudes a lo largo de una cadena de objetos receptores. Cada elemento de la cadena decide si procesa la petición o la transfiere al siguiente. En caso de que ningún componente logre gestionarla, el flujo finaliza lanzando una excepción no controlada.
Singleton y Patrón State
La implementación de un Singleton seguro en entornos concurrentes garantiza la existencia de una única instancia并提供 un punto de acceso global. Al aplicar el patrón State, las clases que representan estados concretos pueden ser diseñadas como Singleotns, ya que al no poseer atributos ni estado interno, su uso es completamente seguro.
Como nota técnica, conviene evaluar la implementación de mecanismos de bloqueo con doble verificación (double-checked locking) junto con el uso de la palabra clave volatile para asegurar una correcta sincronización en lenguajes como Java.
Patrón State
Consiste en abstraer el comportamiento dependiente del estado en objetos independientes, donde cada subclase concreta representa un estado específico. El cliente mantiene una referencia al estado actual y permite que los propios objetos de estado concreto invoquen el método de transición (setState).
A medida que el sistema crece, el acoplamiento directo entre las distintas subclases de estado puede elevar la complejidad. En estos escenarios, es recomendable introducir un Mediador (Mediator) para centralizar y desacoplar las interacciones.
Patrón Command
Encapsula una petición o tarea específica dentro de un objeto. Frecuentemente se integra con el patrón Composite para agrupar comandos. Cada subclase implementa su propia lógica en el método execute().
El componente invocador mantiene una colección de comandos, lo que permite operaciones avanzadas como encolamiento, ejecución retardada, registro de logs o secuenciación.
Patrón Extension Object
Cuando se trabaja con estructuras jerárquicas de árbol donde cada nivel tiene atributos y lógicas de negocio distintas, el patrón Visitor puede concentrar demasiada lógica en una sola clase. Para separar estas operaciones en clases independientes sin alterar la jerarquía original, se utiliza el patrón Extension Object.
Cada nodo de la jerarquía mantiene un diccionario interno de extensiones. Al solicitar una extensión por su tipo, el nodo devuelve el objeto correspondiente que contiene los métodos específicos para operar sobre dicho nodo.
public abstract class NodoJerarquico {
private final Map<TipoExtension, ModuloExtension> extensiones = new ConcurrentHashMap<>();
public abstract String getIdentificador();
public abstract String getDetalle();
public void registrarExtension(TipoExtension tipo, ModuloExtension modulo) {
extensiones.putIfAbsent(tipo, modulo);
}
public ModuloExtension obtenerExtension(TipoExtension tipo) {
return extensiones.getOrDefault(tipo, ModuloExtension.VACIO);
}
}
public enum TipoExtension {
EXPORTACION_XML,
EXPORTACION_CSV
}
public class NodoCompuesto extends NodoJerarquico {
private final String identificador;
private final String detalle;
private final List<NodoJerarquico> subNodos = new CopyOnWriteArrayList<>();
public NodoCompuesto(String identificador, String detalle) {
this.identificador = identificador;
this.detalle = detalle;
}
@Override
public String getIdentificador() { return this.identificador; }
@Override
public String getDetalle() { return this.detalle; }
public List<NodoJerarquico> getSubNodos() { return this.subNodos; }
}
public class NodoHoja extends NodoJerarquico {
private final String identificador;
private final String detalle;
private final double valor;
public NodoHoja(String identificador, String detalle, double valor) {
this.identificador = identificador;
this.detalle = detalle;
this.valor = valor;
registrarExtension(TipoExtension.EXPORTACION_XML, new ExtensionXMLHoja(this));
registrarExtension(TipoExtension.EXPORTACION_CSV, new ExtensionCSVHoja(this));
}
@Override
public String getIdentificador() { return this.identificador; }
@Override
public String getDetalle() { return this.detalle; }
public double getValor() { return this.valor; }
}
public interface ModuloExtension {
ModuloExtension VACIO = new ModuloExtension() {};
}
public interface ExtensionXML extends ModuloExtension {
Object generarElementoXML();
}
public class ExtensionXMLCompuesto implements ExtensionXML {
private final NodoCompuesto nodoCompuesto;
public ExtensionXMLCompuesto(NodoCompuesto nodoCompuesto) {
this.nodoCompuesto = nodoCompuesto;
}
@Override
public Object generarElementoXML() {
List<Object> elementosHijos = new ArrayList<>();
for (NodoJerarquico hijo : nodoCompuesto.getSubNodos()) {
ExtensionXML extXML = (ExtensionXML) hijo.obtenerExtension(TipoExtension.EXPORTACION_XML);
elementosHijos.add(extXML.generarElementoXML());
}
// Ensamblar nodo XML final con elementosHijos
return null;
}
}
public class ExtensionXMLHoja implements ExtensionXML {
private final NodoHoja nodoHoja;
public ExtensionXMLHoja(NodoHoja nodoHoja) {
this.nodoHoja = nodoHoja;
}
@Override
public Object generarElementoXML() {
// Construir elemento XML basado en los atributos de nodoHoja
return new Object();
}
}
Autómatas Finitos y Cambio de Estado
Las máquinas de estados finitos ofrecen un mecanismo abstracto y elegante para modelar el comportamiento de sistemas complejos. La transición entre estados se ejecuta sustituyendo la instancia actual del objeto de estado por otra que representa la nueva situación, facilitando la comprensión y modificación del flujo.
Template Method en Spring
El patrón Método Plantilla delega las partes específicas de un algoritmo a una interfaz, mientras que la estructura general permanece invariante. La clase JdbcTemplate de Spring es un ejemplo clásico, dividiendo el acceso a datos en dos responsabilidades: la plantilla y el callback.
La plantilla estandariza la gestión de recursos, el manejo de transacciones y la conversión de excepciones. Por su parte, el callback se encarga de la lógica variable de la aplicación, como la ejecución de sentencias SQL, la vinculación de parámetros y el mapeo de los resultados.