Behavioral Patterns
Pregunta central
¿Cómo distribuir responsabilidades, algoritmos y comunicación entre colaboradores? Behavioral Patterns agrupa soluciones para variar comportamiento, coordinar operaciones, representar solicitudes, recorrer estructuras y reaccionar a cambios.
La familia GoF contiene once patrones. Esta página conserva sus intenciones y diferencias; no crea once microdocumentos. design-pattern explica el concepto general, pattern-selection trata aplicabilidad y design-patterns organiza navegación.
Los ejemplos propios usan un subsistema de reportes y edición. Cada escenario muestra una presión particular; reconocer varios candidatos no obliga a reunirlos en una sola solución.
Soluciones representativas
Chain of Responsibility
Una solicitud recorre posibles receptores hasta que alguno la atiende. El extracto GoF desarrolla esa colaboración sin fijar un receptor concreto en el emisor. Chain of Responsibility.
En nuestro ejemplo, una consulta de ayuda busca respuesta en el campo, la sección y finalmente el documento. La señal es que el responsable depende del contexto. El costo incluye orden y solicitudes no atendidas. No equivale automáticamente a una pipeline donde todas las etapas deben ejecutar.
Command
Command representa una solicitud como objeto o valor. Nuestro editor puede asociar una acción de exportar a un menú y a un scheduler sin acoplar ambos a la implementación concreta.
La señal es necesitar parametrizar, guardar o despachar una acción. El costo es definir datos, autoridad, lifecycle y resultados. Queueing, logging o undo son posibilidades según implementación, no garantías por nombrar una clase Command. Deshacer una exportación externa requiere una semántica propia.
Interpreter
Representa reglas de un lenguaje y cómo evaluar expresiones. Nuestro diseñador podría admitir una gramática pequeña de condiciones para seleccionar secciones.
La señal es un lenguaje acotado con operaciones repetidas sobre sus expresiones. El riesgo es convertir una jerarquía de nodos en una solución difícil de mantener cuando crece la gramática. Usar un parser o evaluar texto no demuestra por sí solo el patrón; tampoco autoriza interpretar entrada no confiable sin límites.
Iterator
Permite recorrer elementos sin exponer cómo se almacenan. Nuestro reporte podría recorrer observaciones provenientes de distintas colecciones con una conversación común.
La señal es separar traversal y representación. El costo aparece en mutation concurrente, lifetime y liberación de recursos cuando el recorrido es lazy. No garantiza snapshot ni seguridad entre threads. Los protocolos de iteración de un lenguaje pueden proporcionar el mecanismo sin una clase escrita manualmente.
Mediator
Mediator concentra coordinación para reducir referencias directas entre colaboradores. En nuestro editor, cambiar formato afecta opciones de firma y preview; un coordinador expresa esas interacciones sin que cada control conozca todos los demás.
La señal es una red de conversaciones difíciles de modificar. El costo es un mediator que puede crecer y concentrar decisiones sin cohesión. Un simple despachador no demuestra que se hayan reducido las dependencias relevantes. Más abajo se distingue este papel de Service Locator y bibliotecas.
Memento
Captura y restaura estado conservando encapsulación. Nuestro editor podría guardar un estado opaco de la configuración antes de una modificación local, y entregarlo a quien administra el historial.
La señal es restaurar cambios sin revelar todos los detalles internos. El costo incluye memoria, versiones del estado y validez de restauración. No es sinónimo de serializar cualquier objeto ni garantiza rollback de efectos en otros sistemas. Recuperar un borrador no deshace automáticamente un archivo publicado.
Observer
Observer organiza notificación a múltiples dependientes sin que el sujeto conozca sus clases concretas. La señal es mantener interesados informados mediante una conversación compartida.
El canonical desarrolla Push/Pull, suscripciones, lifecycle, orden y failure. La síntesis de familia conserva el límite: notificar no demuestra ejecución asíncrona, entrega durable ni independencia de deployment.
State
State organiza comportamiento que depende del estado interno. Nuestro documento en Draft permite editar y enviar a revisión; en Approved admite otras operaciones. Un objeto puede delegar en representaciones del estado actual.
La señal es comportamiento y transiciones repetidos que resultan difíciles de mantener juntos. El costo es coordinar quién cambia estado y qué transiciones son válidas. Un campo Status o varios if no prueban ni invalidan automáticamente el patrón; interesa el reparto de responsabilidad.
Strategy
Strategy ofrece comportamiento intercambiable detrás de una colaboración estable. La señal es variación independiente del algoritmo, con un propietario claro de su selección.
El canonical compara políticas de precios, funciones y objetos con un conditional directo. El costo incluye selección, contrato e indirection; no obliga a eliminar cada condición ni a crear una clase por fórmula. Su diferencia con State sigue siendo la intención, no la forma de delegación.
Template Method
Conserva un esqueleto de algoritmo y delega pasos a extensiones, clásicamente mediante subclases. Nuestro workflow de exportación mantiene preparación, producción y cierre, permitiendo especializar un paso concreto.
La señal es protocolo estable con variación limitada. El costo es herencia y supuestos sobre orden y hooks. Una extensión puede romper el protocolo si omite una obligación. No equivale a Strategy: aquí se conserva un algoritmo anfitrión con pasos especializables.
Visitor
Separa operaciones sobre una estructura de sus tipos de elementos. Nuestro árbol de secciones podría admitir una operación de análisis nueva sin repartirla entre todos los nodos.
La señal es una estructura relativamente estable con operaciones que cambian. El costo aparece al agregar un nuevo tipo de nodo: pueden necesitar cambios los visitors existentes. No confundirlo con cualquier recorrido; importan el despacho de operaciones y el eje de extensión protegido.
El material académico de CMU sobre GoF permite contrastar estas intenciones. Los escenarios y decisiones anteriores son ejemplos propios, no reproducciones de sus implementaciones.
Strategy y State: intención y control
Ambos pueden delegar comportamiento a otro objeto. Strategy trata alternativas intercambiables; State trata comportamiento y transiciones asociados al estado del contexto.
PricingContext → PricingStrategy
Standard / Premium / Promotional
DocumentContext → CurrentState
Draft → Review → ApprovedEn el primer caso, una decisión de configuración puede seleccionar premiumPricing. En el segundo, una operación cambia lo que el documento puede hacer y bajo qué reglas. Las transiciones pueden controlarse desde el contexto o los estados, según diseño; no existe un único propietario universal.
La alternativa funcional conceptual:
calculatePrice = premiumPricingconserva selección y contrato sin exigir una jerarquía clásica. Funciones, delegates, lambdas, function objects o mapas de comportamiento pueden reducir ceremony. Sigue siendo necesario decidir qué variantes son válidas y quién las suministra.
Observer y event-driven messaging
Observer suele describir colaboración dentro de una frontera de software o proceso. presentation-patterns muestra casos donde notificaciones participan en sincronización de UI. Esa colaboración no implica Event-Driven Architecture, Domain Events ni Integration Events.
Publish/Subscribe messaging añade contratos de canales y suscriptores; el patrón de Publish-Subscribe Channel de Hohpe y Woolf pertenece a otro contexto. Una realización distribuida puede incorporar red, broker, durabilidad, deployment independiente y semántica de entrega.
reliable-messaging y delivery-guarantees permiten analizar esas obligaciones. Un callback registrado no garantiza replay; enviar un mensaje no garantiza una sola ejecución del efecto. El nombre event no crea esas propiedades.
Command y CQRS
Command GoF organiza una solicitud ejecutable y sus colaboradores. Command en CQRS expresa intención de modificar estado dentro de una separación respecto de consultas; puede ser un mensaje de datos manejado por otra parte.
Fowler define CQRS por esa separación de modelos, no por exigir una clase GoF con Execute. Puede haber superposición de mecanismos, pero ninguno implica automáticamente al otro. Un botón conectado a un Command tampoco demuestra CQRS.
Mediator y Service Locator
Mediator coordina interacciones. Service Locator permite obtener colaboradores; esa distinción de resolución se desarrolla en el artículo de Fowler sobre configuración y uso. Un componente que resuelve todo desde un registro no demuestra desacoplamiento por mediación.
Usar MediatR no prueba automáticamente una aplicación adecuada del patrón: es una biblioteca concreta, y el diseño debe mostrar qué interacciones coordina y qué referencias evita. Aquí no se crea su nota tecnológica.
Selección y composición
Un Command puede despacharse mediante un Mediator, una Strategy puede calcular parte de su resultado y un Decorator agregar una responsabilidad. La combinación solo se justifica por presiones distintas y contratos compatibles; no por etiquetar cada llamada.
structural-patterns y creational-patterns pueden colaborar en esas decisiones. Probar comportamiento requiere casos de selección, transición, receptores ausentes y efectos esperados; probar solamente número de tipos o llamadas de mocks no demuestra la intención.
Antes de introducir coordinación adicional, comparar con funciones directas y responsabilidad local. El costo incluye indirection, rastreo de eventos, ownership y lifecycle. Si no existe presión significativa, simplificar puede ser mejor que materializar el patrón.