Bienvenido al primer piso del edificio. En el módulo 1 dejamos los cimientos puestos: sabes qué es un patrón, qué principios encarna y cómo pesar su coste. Ahora toca la primera familia del catálogo GoF, la que gobierna el nacimiento de los objetos. Puede parecer un tema menor —¿qué problema puede haber en hacer new?— pero verás que la instrucción más inocente de Java es, en realidad, el punto de acoplamiento más rígido de todo un sistema. Esta lección presenta el problema común que los cinco patrones creacionales resuelven, te da el mapa de la familia y te enseña a reconocer en el código de PideYa los síntomas de que hace falta uno. Todavía no desarrollaremos ningún patrón: eso empieza en la próxima lección.

Contenido

  1. El problema: new es un contrato de por vida
  2. Por qué crear objetos es una responsabilidad en sí misma
  3. Panorama de los cinco patrones creacionales
  4. Síntomas en PideYa: cómo se nota que falta un creacional
  5. Ámbito de clase vs. ámbito de objeto en los creacionales
  6. Conclusión

El problema: new es un contrato de por vida

Empecemos por un fragmento real del checkout de PideYa, tal como podría haberse escrito en la primera semana del proyecto:

public class ServicioCheckout {

    public void confirmarPedido(Carrito carrito) {
        // Cobrar
        PasarelaStripe pasarela = new PasarelaStripe("sk_live_pideya_2026");
        pasarela.cobrar(carrito.getTotal(), carrito.getCliente().getTarjeta());

        // Avisar al cliente
        NotificadorPush notificador = new NotificadorPush();
        notificador.enviar(carrito.getCliente(), "¡Pedido confirmado!");
    }
}

Funciona. Y sin embargo, cada uno de esos new es una decisión cableada en el código que ata a ServicioCheckout de tres maneras:

  • Ata a una clase concreta. ServicioCheckout no depende de "una pasarela de pago" sino de Stripe en particular. Si mañana negocio firma con Redsys, hay que abrir esta clase y editarla. Es exactamente la violación de DIP que vimos en la lección de principios: un módulo de alto nivel dependiendo de un detalle.
  • Ata al proceso de construcción. ServicioCheckout sabe que la pasarela necesita una clave secreta, y la tiene incrustada. Cualquier cambio en cómo se construye la pasarela (más parámetros, configuración por entorno) propaga cambios hasta aquí.
  • Cierra la puerta a la extensión. Añadir un nuevo canal de notificación o una nueva pasarela obliga a modificar código que ya funcionaba: violación de OCP. Y en los tests, no hay forma de sustituir la pasarela real por un doble: cada test de checkout intentaría cobrar de verdad.

La primera máxima del GoF —«programa contra interfaces, no contra implementaciones»— tiene una letra pequeña que ahora podemos leer: aunque todo tu código use interfaces (PasarelaPago, Notificador), en algún sitio alguien tiene que escribir el new de la clase concreta. Las interfaces no se instancian. Los patrones creacionales responden precisamente a la pregunta que esa letra pequeña deja abierta:

¿Dónde, cómo y quién decide qué clase concreta se instancia, para que el resto del sistema no tenga que saberlo?

Por qué crear objetos es una responsabilidad en sí misma

La idea central de toda la familia se puede resumir así: crear un objeto es una responsabilidad, y como toda responsabilidad (SRP), merece a veces su propia clase o su propio método. Los patrones creacionales encapsulan dos tipos de conocimiento para que no se dispersen por el sistema:

  1. Qué se crea: qué clase concreta se instancia (¿PasarelaStripe o PasarelaRedsys? ¿NotificadorPush o NotificadorSms?).
  2. Cómo se crea: qué pasos, parámetros, validaciones u objetos colaboradores hacen falta para dejar la instancia lista para usar.

Cuando ese conocimiento está encapsulado, el código cliente trabaja solo contra interfaces y el sistema gana la propiedad que perseguimos desde el módulo 1: los ejes de cambio reales (nueva pasarela, nuevo país, nuevo canal) se absorben añadiendo piezas, no modificando las existentes.

Un matiz importante que conviene fijar desde ya: los creacionales no eliminan el new, lo reubican. El new PasarelaStripe(...) seguirá existiendo, pero vivirá en un único lugar diseñado para ello (una fábrica, un builder, un método de creación), en vez de estar repartido por veinte clases de negocio.

Panorama de los cinco patrones creacionales

El GoF cataloga cinco patrones creacionales. Aquí tienes el mapa de la familia en una línea por patrón; cada uno tendrá su lección completa en este módulo:

Patrón Idea en una línea Lección
Singleton Garantizar que una clase tiene una única instancia y dar un punto de acceso global a ella 02-02
Factory Method Delegar en subclases la decisión de qué clase concreta instanciar, tras un método de creación 02-03
Abstract Factory Crear familias de objetos relacionados (que deben combinarse entre sí) sin nombrar sus clases concretas 02-04
Builder Construir paso a paso objetos complejos, separando la construcción de la representación final 02-05
Prototype Crear objetos nuevos clonando una instancia existente en vez de instanciar una clase 02-06

Fíjate en que cada patrón ataca una arista distinta del mismo problema:

  • Singleton controla cuántas instancias existen.
  • Factory Method y Abstract Factory controlan qué clase concreta se elige (uno para un producto, otro para familias enteras).
  • Builder controla el proceso de construcción cuando es largo o tiene variantes.
  • Prototype controla la fuente: el nuevo objeto no nace de una clase sino de otro objeto.

En la comparativa final del módulo los enfrentaremos entre sí y verás cómo se combinan; de momento basta con este mapa.

Síntomas en PideYa: cómo se nota que falta un creacional

Como aprendimos en la lección de la balanza, los patrones se ganan, no se plantan: se llega a ellos cuando el código duele. Estos son los dolores concretos —todos reales en el crecimiento de una plataforma como PideYa— que señalan hacia esta familia. Guárdalos como lista de diagnóstico; las lecciones siguientes los irán resolviendo uno a uno:

  • new de clases concretas repartidos por el código de negocio. Buscar new PasarelaStripe devuelve doce resultados en siete clases. Cambiar de proveedor es una operación quirúrgica a corazón abierto. → El conocimiento de qué crear pide ser centralizado (Factory Method).
  • Un switch o cadena de if sobre un "tipo" que decide qué instanciar, duplicado allá donde se necesita el objeto:
// Este bloque aparece, con variaciones, en tres servicios distintos de PideYa
Notificador n;
switch (canalPreferido) {
    case PUSH:  n = new NotificadorPush(); break;
    case SMS:   n = new NotificadorSms(claveTwilio); break;
    case EMAIL: n = new NotificadorEmail(servidorSmtp); break;
    default: throw new IllegalArgumentException(canalPreferido.toString());
}

Cada canal nuevo obliga a encontrar y editar todas las copias. → Centralizar la decisión (Factory Method).

  • Objetos que deben ser coherentes entre sí y nadie lo garantiza. Al abrir PideYa en México, un despiste combinó la pasarela mexicana con la calculadora de IVA español: cobros mal calculados en producción. Las piezas se creaban sueltas y nada impedía mezclar familias. → Crear la familia completa de una vez (Abstract Factory).
  • Constructores telescópicos. El constructor de Pedido ha ido engordando con cada sprint hasta volverse ilegible e imposible de llamar sin consultar la firma:
Pedido p = new Pedido(cliente, lineas, direccion, null, null, "sin cebolla",
                      true, null, FranjaHoraria.MEDIODIA, false);
// ¿Qué es cada null? ¿Qué significa el true? Nadie lo sabe sin mirar la firma.

→ Construcción paso a paso, legible y validada (Builder).

  • Crear un objeto "casi igual" a otro existente cuesta reconstruirlo entero. La función "repetir mi último pedido" de la app copia campo a campo el pedido anterior, y cada vez que Pedido gana un atributo alguien olvida copiarlo. → Clonar en vez de reconstruir (Prototype).
  • Estado global casero. La configuración de la plataforma (comisiones, radios de reparto) se carga tres veces desde disco porque cada servicio hace su propia copia, y en producción dos copias quedaron desincronizadas. → Controlar la unicidad (Singleton... con las alertas que veremos).
  • Tests que no pueden aislar al sujeto. Probar ServicioCheckout exige red, claves reales y paciencia, porque sus colaboradores se instancian dentro con new y no hay forma de colar un doble de prueba.

Si reconoces varios de estos síntomas en un código, tienes un problema nombrable sin citar patrón alguno (primer filtro de la lección anterior): la creación de objetos se ha convertido en un eje de cambio real y dolorido. Ese es el momento —y no antes— de abrir el catálogo creacional.

Ámbito de clase vs. ámbito de objeto en los creacionales

En la clasificación del catálogo vimos que el GoF cruza el propósito (creacional, estructural, de comportamiento) con el ámbito: si el patrón fija su solución mediante herencia (ámbito de clase, decidido en compilación) o mediante composición y delegación (ámbito de objeto, configurable en ejecución). En los creacionales el reparto es muy asimétrico:

Ámbito Patrones Mecanismo de variación
Clase Factory Method Se varía heredando: cada subclase del creador redefine qué producto instancia. La elección queda fijada por la subclase que uses.
Objeto Abstract Factory, Builder, Prototype, Singleton Se varía componiendo: el cliente recibe (o localiza) un objeto —una fábrica, un builder, un prototipo— y puede cambiarse por otro en tiempo de ejecución.

Esta asimetría no es casual: refleja la segunda máxima del GoF, «favorece la composición sobre la herencia». Cuatro de los cinco creacionales delegan la creación en un objeto que se puede inyectar, sustituir o configurar sin recompilar; solo Factory Method se apoya en la herencia, y aun así veremos en su lección variantes modernas (lambdas, genéricos) que lo desplazan también hacia la composición. Cuando estudies cada patrón, pregúntate siempre en qué ámbito está: te dirá cuándo se decide la clase concreta (al compilar o al ejecutar) y, por tanto, cuánta flexibilidad compras y a qué precio.

Errores Comunes y Consejos

  • Creer que el objetivo es "prohibir el new". No: el objetivo es que el new de cada clase concreta viva en un único lugar con nombre propio. Un new ArrayList<>() local, o el new de un objeto de valor simple como Dinero, no necesitan patrón alguno.
  • Empezar el diseño eligiendo el patrón. El orden correcto es síntoma → problema → patrón. Si el checkout de PideYa tuviera una sola pasarela estable desde hace años, los new directos serían perfectamente defendibles (YAGNI).
  • Confundir los patrones entre sí antes de estudiarlos. Es normal que ahora mismo Factory Method y Abstract Factory te suenen iguales; no intentes distinguirlos aún de memoria. Las lecciones siguientes los separan con ejemplos, y la comparativa los pondrá frente a frente.
  • Olvidar los tests como síntoma. "No puedo testear esta clase sin levantar medio sistema" es de los indicadores más fiables de que la creación está mal ubicada. Escucha a tus tests: son el primer cliente de tu diseño.

Ejercicios

Ejercicio 1: cazar los acoplamientos

En este fragmento del servicio de alta de restaurantes de PideYa, identifica todos los puntos donde el código queda acoplado a una clase concreta o a un proceso de construcción, y clasifica cada uno según el síntoma de la sección 4 que mejor lo describa:

public class ServicioAltaRestaurante {

    public void darDeAlta(DatosRestaurante datos) {
        ValidadorCif validador = new ValidadorCif();
        if (!validador.validar(datos.getCif())) throw new CifInvalidoException();

        Restaurante r = new Restaurante(datos.getNombre(), datos.getCif(),
                datos.getDireccion(), null, null, true, false, null, 30, null);

        NotificadorEmail email = new NotificadorEmail("smtp.pideya.com", 587, "[email protected]");
        email.enviar(datos.getEmailContacto(), "Bienvenido a PideYa");
    }
}

Ejercicio 2: asignar patrón a cada síntoma

Sin implementar nada (aún no sabes cómo), indica qué patrón creacional del panorama de la sección 3 parece apuntar a cada situación de PideYa, y justifica en una frase:

  1. La app permite "duplicar" una carta de restaurante entera para crear la carta del turno de noche con pequeños cambios.
  2. Los repartidores autónomos y los de flota propia requieren objetos distintos de contrato, seguro y liquidación, que deben ser siempre del mismo régimen entre sí.
  3. El objeto Factura tiene 4 campos obligatorios y 9 opcionales, y su constructor es inmanejable.
  4. La conexión al broker de mensajería debe ser una sola para todo el proceso y accesible desde varios servicios.
  5. El servicio de avisos debe crear el notificador adecuado (push, SMS, email) según la preferencia del cliente, y hoy lo hace con un switch repetido en tres clases.

Ejercicio 3: ¿patrón o YAGNI?

PideYa genera un identificador de pedido con new GeneradorIdPedido().siguiente(). El generador no tiene estado de configuración, existe una sola implementación y no hay planes de cambiarla. Un compañero propone "prepararlo para el futuro" con una fábrica. Aplica los filtros de la lección 01-06 y da tu veredicto.

Soluciones

Solución 1:

  • new ValidadorCif(): dependencia de clase concreta dentro del negocio; impide sustituirla por un doble en tests (síntoma "tests que no pueden aislar al sujeto" y "new repartidos").
  • new Restaurante(...) con diez argumentos, varios null y literales sin nombre (true, false, 30): constructor telescópico de manual (síntoma → Builder).
  • new NotificadorEmail("smtp...", 587, ...): doble acoplamiento, a la clase concreta (¿y si el cliente prefiere SMS?) y al proceso de construcción (host y puerto cableados aquí, que es el peor lugar para ellos). Síntomas "new repartidos" y conocimiento de construcción disperso (→ Factory Method).

Solución 2:

  1. Prototype: el objeto nuevo nace clonando una carta existente, no reconstruyéndola de cero.
  2. Abstract Factory: contrato + seguro + liquidación forman una familia que debe mantenerse coherente (todo del régimen autónomo o todo de flota).
  3. Builder: construcción paso a paso con obligatorios y opcionales, validando al final.
  4. Singleton (con las reservas que veremos en la próxima lección): unicidad de instancia y acceso compartido.
  5. Factory Method: centralizar en un método de creación la decisión de qué notificador concreto instanciar.

Solución 3: falla el filtro 2 (el eje de cambio es especulativo: una sola implementación, sin planes) y el 3 (el código simple no duele: el generador no tiene dependencias que dificulten tests). Veredicto: no introducir fábrica; a lo sumo, si GeneradorIdPedido se usa en clases que quieren testearse de forma determinista, inyectarlo como colaborador (DIP básico) sin patrón adicional. La fábrica se ganará el día que exista una segunda forma real de generar identificadores.

Conclusión

Ya tienes el mapa de la familia creacional: el enemigo común es el acoplamiento que cada new cablea entre el código de negocio y las clases concretas (con OCP y DIP como principios heridos), y los cinco patrones son cinco maneras de encapsular la creación —controlando cuántas instancias hay, qué clase se elige, cómo se construye o desde qué objeto se clona—. También sabes leer los síntomas que justifican abrirlos y en qué ámbito (clase u objeto) juega cada uno.

Empezamos el desfile por el patrón más famoso, el más corto de escribir... y el más discutido de todo el catálogo: garantizar que algo exista una sola vez es fácil; hacerlo sin crear un problema mayor, no tanto. Nos vemos en Singleton.

Curso de Patrones de Diseño de Software

Módulo 1: Introducción a los Patrones de Diseño

Módulo 2: Patrones Creacionales

Módulo 3: Patrones Estructurales

Módulo 4: Patrones de Comportamiento

Módulo 5: Aplicación de Patrones de Diseño

Módulo 6: Patrones de Diseño Avanzados

Módulo 7: Recursos Adicionales y Conclusión

© Copyright 2026. Todos los derechos reservados