Clase 12 — Cierre de Patrones de Diseño y Orientación al Examen
Resumen Ejecutivo
Sesión de cierre del Tema 7 con tres bloques. Primero, repaso de los últimos patrones de comportamiento GoF: Cadena de Responsabilidad, Mediador, Observador y Estado, con ejemplos en JavaScript y discusión sobre combinaciones entre patrones. Segundo, revisión de los patrones de diseño de interfaz de usuario (catálogos de UI patterns), diferenciándolos explícitamente de los patrones de diseño de clases. Tercero, orientación detallada al examen: estructura, apartados, criterios de corrección, tipos de aplicación que pueden aparecer y consejos específicos sobre historias de usuario, planificación de sprints y estimación de tareas. ⚠️ EXAMEN: todo el bloque de orientación es material crítico para preparar el examen.
Conceptos Clave
- Cadena de Responsabilidad: Patrón de comportamiento en el que una solicitud se pasa por una cadena de objetos hasta que uno la procesa. Desacopla emisor y receptor. ⚠️ EXAMEN
- Diferencia Cadena de Responsabilidad vs Tuberías y Filtros: En Tuberías y Filtros la información se transforma secuencialmente en cada filtro; en Cadena de Responsabilidad la solicitud no se transforma, sino que se pasa hasta encontrar el objeto capaz de procesarla (la cadena puede no ejecutarse entera). ⚠️ EXAMEN
- Mediador: Objeto central que centraliza y orquesta la comunicación entre muchos objetos con alto acoplamiento mutuo. Compatible con el patrón Observador (el mediador es el observador de todos los elementos). ⚠️ EXAMEN
- Observador: Patrón sujeto/observador. Los sujetos notifican cambios de estado; los observadores se suscriben (
attach) y desuscriben (detach). ⚠️ EXAMEN - Estado: El comportamiento de un objeto cambia según su estado interno. Se evitan grandes bloques
switch/ifextrayendo cada estado a una clase especializada. ⚠️ EXAMEN - Patrones de diseño de interfaz: Catálogos de soluciones recurrentes para problemas de UX/UI (carrusel, checklist, password strength indicator...). Son completamente distintos a los patrones GoF.
- Estructura del examen: Pregunta teórica (3 puntos, elegir 1 de 2) + ejercicio de proyecto (7 puntos, 4 apartados relacionados con actividades 1 y 2).
Desarrollo del Temario
1. Patrón Cadena de Responsabilidad
Problema: el cliente no sabe qué objeto es capaz de procesar una solicitud. Si lo resuelve consultando directamente a cada receptor en secuencia, el código queda muy acoplado y es difícil de escalar.
Solución: definir una interfaz Handler con un método handle y un enlace al siguiente manejador. Cada manejador concreto procesa lo que puede y pasa el resto al siguiente.
// Clase base (en JS aproximamos clase abstracta)
class Handler {
setNext(handler) {
this.next = handler;
return handler;
}
handle(request) {
if (this.next) return this.next.handle(request);
return null;
}
}
// Manejador concreto
class EmailValidator extends Handler {
handle(request) {
if (!request.email || !request.email.includes('@')) {
return 'Error: email inválido';
}
return super.handle(request); // pasa al siguiente
}
}
class PasswordValidator extends Handler {
handle(request) {
if (!request.password || request.password.length < 6) {
return 'Error: contraseña muy corta';
}
return super.handle(request);
}
}
// Configurar la cadena
function validateForm(request) {
const emailValidator = new EmailValidator();
const passwordValidator = new PasswordValidator();
emailValidator.setNext(passwordValidator);
return emailValidator.handle(request);
}
Características clave: - El orden de la cadena lo define quien la construye, no las propias clases. - La cadena no siempre se recorre entera: se detiene cuando un manejador no puede pasar al siguiente o cuando hay un error. - Compatible con el patrón Builder para construir la cadena. - Compatible con el patrón Composite: en jerarquías de objetos, el padre transmite solicitudes a los hijos.
Diferencia con Tuberías y Filtros: ⚠️ EXAMEN
| Cadena de Responsabilidad | Tuberías y Filtros | |
|---|---|---|
| Naturaleza | Solicitud/evento que busca receptor | Dato que sufre transformaciones |
| Ejecución | Puede detenerse antes de acabar | Siempre recorre todos los filtros |
| Transformación | No transforma (busca quién procesa) | Transforma en cada etapa |
| Nivel | Patrón de diseño detallado | Patrón arquitectónico |
Ejemplo práctico: abrir un fichero en el explorador del SO. El sistema pasa la ruta por una cadena de manejadores (por extensión, por cabecera binaria...) hasta encontrar el programa capaz de abrirlo.
Beneficios: mejor cohesión (cada clase valida solo una cosa), menor acoplamiento (emisor no conoce al receptor final), fácil de extender sin modificar clases existentes.
2. Patrón Mediador
Problema: muchos objetos se comunican entre sí, generando una maraña de acoplamientos. Ejemplo: formulario con muchos campos donde la habilitación de un botón depende de varios campos.
Solución: un objeto central (el Mediador) conoce a todos los colaboradores y centraliza la lógica de coordinación. Los colaboradores ya no se conocen entre sí.
Combinación con Observador: ⚠️ EXAMEN El mediador es el observador de todos los objetos del formulario. Cada vez que un campo cambia (evento keyChange), notifica al mediador, que actualiza el estado de la interfaz. Así:
- Solo el mediador tiene lógica de coordinación.
- Si la lógica se complica, se puede refactorizar solo el mediador.
- Los colaboradores quedan simples y desacoplados entre sí.
Ventaja e inconveniente: el mediador puede convertirse en un objeto muy complejo. Sin embargo, esa complejidad está concentrada en un único lugar, lo que es preferible a tenerla dispersa por toda la aplicación.
Relación con arquitectura de microservicios: los orquestadores de microservicios y los orquestadores de agentes de IA son conceptualmente similares al mediador: un componente central que coordina la colaboración entre muchos servicios/agentes.
classDiagram
class Mediador {
-colaboradores: List
+notify(origen, evento)
}
class Campo1 {
-mediador: Mediador
+onChange()
}
class Campo2 {
-mediador: Mediador
+onChange()
}
class Boton {
+setEnabled(bool)
}
Mediador o-- Campo1
Mediador o-- Campo2
Mediador o-- Boton
3. Patrón Observador
Patrón sujeto-observador para notificar cambios de estado a múltiples objetos.
Roles:
- Sujeto: produce cambios de estado. Implementa attach(observer), detach(observer) y notify().
- Observador: se suscribe al sujeto y recibe notificaciones mediante update().
Funcionamiento:
1. Los observadores hacen attach(self) en el sujeto.
2. Cuando el sujeto cambia, llama a notify() que recorre su lista e invoca update() en cada observador.
3. El observador puede pedir el nuevo estado con getState().
Compatibilidad: un observador puede establecer, a su vez, una cadena de responsabilidad con los otros observadores.
Regla mnemotécnica: el observador es "la vieja del visillo": está detrás de su visillo observando a los sujetos que pasan.
4. Patrón Estado
Problema: el comportamiento de un objeto depende de combinaciones de atributos internos. El resultado son grandes bloques switch o anidaciones de if que generan código espagueti.
Solución: extraer el código asociado a cada estado a una clase especializada. El objeto contexto delega la operación en el objeto de estado actual. Si el estado cambia (p. ej. el objeto "bebe una poción envenenada"), el contexto instancia el objeto de estado nuevo.
Ejemplo conceptual (videojuego):
Elfo (contexto)
estado = ElfoNormal | ElfoMalito | ElfoNigromante
beber(poción) → delega en estado.beber(poción)
→ estado cambia según resultado
Beneficio: cada clase de estado es pequeña, cohesionada y fácil de mantener. Añadir un nuevo estado no modifica los existentes.
5. Patrones de Diseño de Interfaz de Usuario
Diferencia crítica con los patrones GoF: ⚠️ EXAMEN Los patrones de UI (catálogos como ui-patterns.com) son soluciones recurrentes a problemas de diseño visual e interacción con el usuario. No tienen nada que ver con diagramas de clases, interfaces ni herencia.
Categorías habituales: - Obtener información del usuario (formularios, checkboxes, password strength) - Navegación (carrusel, breadcrumb, pagination) - Feedback al usuario (progress bar, notificaciones, mensajes de error) - Trabajando con datos (tablas, búsqueda, filtros)
Error frecuente en los trabajos: mezclar ambos tipos de patrones en el mismo apartado del trabajo o confundir el observador con un patrón de interfaz. En la actividad: el último apartado pide patrones de UI, no patrones GoF.
6. Orientación al Examen ⚠️ EXAMEN
6.1 Estructura del examen
| Parte | Descripción | Puntos |
|---|---|---|
| Pregunta teórica | Elegir 1 de 2 preguntas sobre temario | 3 |
| Ejercicio de proyecto | 4 apartados sobre una aplicación ficticia | 7 |
Materiales permitidos: calculadora básica (útil para sumas de horas en planificación). En examen online: folios en blanco para dibujar, fotografiados y subidos.
Los diagramas deben hacerse a mano (no se permite draw.io ni herramientas de dibujo). Los enunciados estarán como adjunto en la plataforma del examen.
6.2 Pregunta teórica
- Dos opciones a elegir; pueden ser del mismo tema o de temas distintos.
- Una página de espacio.
- Hay un documento de orientaciones en el aula (sección Documentación) con lo más importante de cada tema.
- Patrones que hay que conocer sí o sí según el profesor: Web Queue Worker, CQRS (Command and Query Responsibility Segregation), y los patrones GoF vistos en clase.
- Metodologías ágiles (Scrum): roles, artefactos, ceremonias. Saber explicar el esquema general.
6.3 Ejercicio de proyecto (7 puntos)
La aplicación será inventada por el profesor en el momento (aplicación móvil, web o de escritorio). Puede ser cualquier cosa: app de aparcamientos, recetas de cocina, traducción instantánea con cámara, resultados de petanca de Zamora... El tipo de plataforma (móvil/web/escritorio) condiciona qué patrones tienen sentido.
Los 4 apartados:
Apartado 1 — Historias de usuario
- Redactar historias con el formato: Como <rol>, necesito <funcionalidad> para <objetivo>.
- ⚠️ EXAMEN: no incluir historias triviales ni genéricas (cambiar foto de perfil, registrarse...). Deben ser específicas del dominio de la aplicación propuesta.
- Las historias triviales o genéricas no puntúan.
Apartado 2 — Planificación del sprint - Seleccionar 5 historias para la pila de producto y planificar un sprint con 3 de ellas. - Descomponer las 3 en tareas con estimaciones de horas. - Definir el equipo (número de personas, horas disponibles). - La planificación debe ser coherente con la capacidad real del equipo. ⚠️ EXAMEN - No dejar márgenes genéricos masivos; si hay incertidumbre, modelarla a nivel de tarea concreta. - Las historias seleccionadas deben respetar las prioridades del Product Owner, no las preferencias del alumno. - No se pide Kanban ni burndown chart.
Criterios de corrección de la planificación: - Las horas de las tareas del sprint deben sumar aproximadamente lo que el equipo puede hacer. - Justificar el tiempo dedicado a ceremonias (daily, revisión, retrospectiva) como tareas concretas, no como porcentajes de holgura. - Si se planifica por debajo de la capacidad, tener una historia en "recámara" lista para añadir si sobra tiempo.
Apartado 3 — Diseño arquitectónico general - Diagrama de arquitectura general aplicando 3 patrones arquitectónicos. - Por cada patrón: tabla con nombre, problema que resuelve y diagrama. - El diagrama debe estar dibujado por el alumno, no copiado de ninguna fuente. - El tipo de plataforma importa: no tiene sentido un patrón de microservicios en una app de escritorio simple sin justificación.
Apartado 4 — Diseño detallado con patrones GoF - Identificar 2 problemas de comportamiento/estructurales del software. - Por cada problema: indicar el patrón GoF que lo resuelve y dibujar el diagrama de clases. - Para el Singleton hay que representar los elementos específicos del patrón. - No hay que escribir código, pero sí dibujar el diagrama correctamente.
6.4 Errores frecuentes que penalizan
- Historias de usuario triviales o genéricas (no específicas del dominio).
- Planificación con capacidad del equipo muy por debajo de lo posible (márgenes del 40-50%).
- Mezclar patrones GoF con patrones de UI en el mismo apartado.
- Copiar diagramas de internet o de la presentación del profesor.
- Seleccionar historias de prioridad baja sin justificar por qué se incluyeron.
- Diagramas de arquitectura generados por IA con errores evidentes (grafos ASCII sin sentido, flechas aleatorias).
- CDN descrito como servidor de aplicaciones (error conceptual grave).
Preguntas de Autoevaluación
- ⚠️ EXAMEN: Explica la diferencia entre Cadena de Responsabilidad y el patrón de Tuberías y Filtros. Da un ejemplo de cuándo usarías cada uno.
- ¿Por qué el Mediador puede combinarse con el Observador? ¿Cuál sería el rol de cada uno en un formulario con muchos campos interdependientes?
- ¿Cuáles son las tres responsabilidades de la interfaz del Sujeto en el patrón Observador?
- En el patrón Estado, ¿qué ventaja tiene crear clases especializadas por estado frente a usar un gran bloque
switch? - ⚠️ EXAMEN: ¿Qué diferencia hay entre un patrón de diseño GoF y un patrón de diseño de interfaz de usuario? Da un ejemplo de cada tipo.
- Cómo deben redactarse las historias de usuario en el examen. ¿Qué tipo de historias NO puntúan?
- ⚠️ EXAMEN: ¿Por qué no tiene sentido dejar un margen genérico del 20% en la planificación del sprint? ¿Dónde debe modelarse la incertidumbre?
- ¿Quién decide qué historias entran en el sprint y con qué prioridad? ¿Puede el alumno/desarrollador cambiar ese orden por su cuenta?
- ¿Qué materiales están permitidos en el examen y para qué sirve la calculadora?
- En el apartado de diseño detallado, ¿qué dos cosas hay que incluir por cada patrón GoF identificado?