Problema

Crear objetos sin especificar su clase exacta, delegando la decisión de instanciación a las subclases.

Propósito

Definir una interfaz para crear objetos, pero permitir que las subclases decidan qué clase instanciar. Encapsula la lógica de creación y reduce el acoplamiento entre el código cliente y las clases concretas.

Casos de uso comunes

  • Creadores de documentos (PDF, Word, Excel)
  • Servicios de notificación (email, SMS, push)
  • Parsers de diferentes formatos (JSON, XML, CSV)
  • Loggers con diferentes destinos (archivo, consola, red)
  • Conexiones de base de datos (MySQL, PostgreSQL, MongoDB)

¿Quién es quién en Factory Method?

Actor Lo que realmente es Ejemplo Analogía
Creator Clase abstracta con factory method y lógica común DocumentCreator - define createDocument() “Fábrica” (proceso general)
ConcreteCreator Creadores que saben qué producto crear PDFCreator, WordCreator Fábrica de autos, fábrica de motos
Product Interfaz que define qué pueden hacer Document - define open(), save(), close() “Vehículo” (qué puede hacer)
ConcreteProduct Implementaciones reales de productos PDFDocument, WordDocument Auto, Moto (vehículos específicos)

Clave: El cliente conoce el Creator pero NO el Product concreto

Diagrama

classDiagram
    namespace FactoryMethod {
        class Creator {
            <<abstract>>
            +factoryMethod() Product
            +someOperation()
        }
        
        class ConcreteCreatorA {
            +factoryMethod() ProductA
        }
        
        class ConcreteCreatorB {
            +factoryMethod() ProductB
        }
        
        class Product {
            <<interface>>
            +doSomething()
        }
        
        class ProductA {
            +doSomething()
        }
        
        class ProductB {
            +doSomething()
        }
    }
    
    Creator <|-- ConcreteCreatorA
    Creator <|-- ConcreteCreatorB
    Product <|.. ProductA
    Product <|.. ProductB
    ConcreteCreatorA --> ProductA : creates
    ConcreteCreatorB --> ProductB : creates

Ejemplo práctico

classDiagram
    namespace DocumentExample {
        class Client {
            +main()
        }
        
        class DocumentCreator {
            <<abstract>>
            +createDocument() Document
            +processDocument()
        }
        
        class PDFCreator {
            +createDocument() PDFDocument
        }
        
        class WordCreator {
            +createDocument() WordDocument
        }
        
        class ExcelCreator {
            +createDocument() ExcelDocument
        }
        
        class Document {
            <<interface>>
            +open()
            +save()
            +close()
        }
        
        class PDFDocument {
            +open()
            +save()
            +close()
        }
        
        class WordDocument {
            +open()
            +save()
            +close()
        }
        
        class ExcelDocument {
            +open()
            +save()
            +close()
        }
    }
    
    Client --> DocumentCreator
    Client --> Document
    DocumentCreator <|-- PDFCreator
    DocumentCreator <|-- WordCreator
    DocumentCreator <|-- ExcelCreator
    Document <|.. PDFDocument
    Document <|.. WordDocument
    Document <|.. ExcelDocument
    PDFCreator --> PDFDocument : creates
    WordCreator --> WordDocument : creates
    ExcelCreator --> ExcelDocument : creates

Flujo de creación

sequenceDiagram
    participant Client
    participant PDFCreator
    participant PDFDocument
    
    Note over Client: 1. Cliente instancia creator concreto
    Client->>PDFCreator: new PDFCreator()
    PDFCreator-->>Client: creator instance
    
    Note over Client: 2. Cliente solicita procesamiento
    Client->>PDFCreator: processDocument()
    PDFCreator->>PDFCreator: createDocument()
    PDFCreator->>PDFDocument: new PDFDocument()
    PDFDocument-->>PDFCreator: document instance
    
    Note over Client: 3. Creator usa el documento creado
    PDFCreator->>PDFDocument: open()
    PDFCreator->>PDFDocument: save()
    PDFCreator->>PDFDocument: close()
    PDFCreator-->>Client: processing complete
    
    Note over Client, PDFDocument: El cliente conoce PDFCreator pero no PDFDocument

Limitación importante

En Factory Method puro, el cliente debe conocer qué creator concreto usar:

// Cliente DEBE decidir qué creator usar
const creator = new PDFCreator();  // Cliente conoce PDFCreator
const doc = creator.processDocument(); // Pero NO conoce PDFDocument
doc.open(); // Usa polimorfismo

El patrón desacopla:

  • ✅ Cliente de productos concretos
  • ❌ Cliente de creators concretos

Ventajas

  • Desacoplamiento: Elimina dependencias directas con clases concretas
  • Extensibilidad: Fácil agregar nuevos productos sin modificar código existente
  • Polimorfismo: Permite crear objetos basados en parámetros o contexto
  • Single Responsibility: Separa la lógica de creación de la lógica de negocio

Desventajas

  • Complejidad: Introduce más clases e interfaces
  • Jerarquías paralelas: Cada producto requiere su creator correspondiente
  • Overhead: Puede ser excesivo para casos simples

Cuándo usar

  • Necesitas crear objetos sin conocer su clase exacta
  • Quieres delegar la decisión de creación a subclases
  • Tienes múltiples implementaciones de una interfaz
  • La lógica de creación es compleja o puede cambiar

Cuándo NO usar

  • Solo tienes una implementación
  • La creación es simple y no cambiará
  • No necesitas polimorfismo en la creación

Variaciones del patrón

graph TB
    A[Factory Method Variations] --> B[Simple Factory]
    A --> C[Factory Method]
    A --> D[Abstract Factory]
    A --> E[Static Factory]
    
    B --> B1["Una clase con método estático<br/>No es patrón GoF"]
    C --> C1["Subclases deciden qué crear<br/>Patrón GoF clásico"]
    D --> D1["Familias de productos relacionados<br/>Múltiples factory methods"]
    E --> E1["Métodos estáticos de creación<br/>valueOf(), of(), getInstance()"]

Simple Factory

classDiagram
    namespace SimpleFactoryComparison {
        class Client {
            +main()
        }
        
        class DocumentFactory {
            +createDocument(type) Document
        }
        
        class Document {
            <<interface>>
            +open()
            +save()
            +close()
        }
        
        class PDFDocument {
            +open()
            +save()
            +close()
        }
        
        class WordDocument {
            +open()
            +save()
            +close()
        }
    }
    
    Client --> DocumentFactory
    Client --> Document
    DocumentFactory --> PDFDocument : creates
    DocumentFactory --> WordDocument : creates
    Document <|.. PDFDocument
    Document <|.. WordDocument

Simple Factory vs Factory Method:

Aspecto Simple Factory Factory Method
Estructura Una clase con switch/if Jerarquía de clases
Extensibilidad Modificar factory existente Agregar nueva subclase
Cliente conoce Solo la factory Creator concreto
Complejidad Menor Mayor
Flexibilidad Menor Mayor