
Patrones de Diseño: Factory
- Dacadev
- Programación
- 7 de julio de 2026
Tabla de Contenido
La instanciación directa de clases concretas es uno de los puntos más costosos de acoplamiento en un diseño orientado a objetos. Cada new o llamada explícita a un constructor ata al cliente a una implementación específica, dificultando la extensión y la sustitución de componentes. Los patrones factory encapsulan esa decisión en un lugar controlado, permitiendo evolucionar la creación de objetos sin propagar cambios a todo el código consumidor.
Note
🚀 Los patrones factory encapsulan la creación de objetos y desacoplan al cliente de las clases concretas que necesita instanciar.
Este artículo forma parte de la serie de patrones de diseño. Analizaremos tres variantes de fabricación (Simple Factory, Factory Method y Abstract Factory), su relación con el Principio de Inversión de Dependencias y los trade-offs que conviene considerar al elegir uno u otro.
Simple Factory
El Simple Factory no es un patrón de diseño formal del catálogo GoF, sino un idiom recurrente: encapsular la lógica de creación de objetos dentro de un método (usualmente estático) que decide qué instancia devolver en función de un parámetro. Es un buen punto de partida para entender los patrones que veremos a continuación.
Info
GoF significa “Gang of Four” (la “Banda de los Cuatro”): los cuatro autores del libro Design Patterns (1994) que catalogó los 23 patrones de diseño clásicos. Cuando decimos que un patrón “es GoF”, significa que aparece en ese catálogo original.
Supongamos una pizzería que produce distintos tipos de pizzas. Sin un factory, el cliente tendría que conocer todas las clases concretas y decidir cuál instanciar. Con un SimpleFactory esa decisión queda centralizada:
classDiagram
class PizzaStore {
-factory: SimplePizzaFactory
+order_pizza(kind) Pizza
}
class SimplePizzaFactory {
+create_pizza(kind) Pizza
}
class Pizza {
<<abstract>>
+prepare()
+bake()
+box()
}
class CheesePizza
class VeggiePizza
class PepperoniPizza
PizzaStore --> SimplePizzaFactory : usa
SimplePizzaFactory ..> Pizza : crea
Pizza <|-- CheesePizza
Pizza <|-- VeggiePizza
Pizza <|-- PepperoniPizza
Implementación mínima en Python:
from abc import ABC, abstractmethod
class Pizza(ABC):
@abstractmethod
def prepare(self) -> None: ...
def bake(self) -> None:
print("Horneando la pizza")
def box(self) -> None:
print("Empacando la pizza")
class CheesePizza(Pizza):
def prepare(self) -> None:
print("Preparando pizza de queso")
class VeggiePizza(Pizza):
def prepare(self) -> None:
print("Preparando pizza vegetariana")
class SimplePizzaFactory:
def create_pizza(self, kind: str) -> Pizza:
if kind == "cheese":
return CheesePizza()
if kind == "veggie":
return VeggiePizza()
raise ValueError(f"Tipo de pizza no soportado: {kind}")
class PizzaStore:
def __init__(self, factory: SimplePizzaFactory) -> None:
self.factory = factory
def order_pizza(self, kind: str) -> Pizza:
pizza = self.factory.create_pizza(kind)
pizza.prepare()
pizza.bake()
pizza.box()
return pizza
El cliente (PizzaStore) ya no depende de las clases concretas; toda la lógica de selección vive en el factory. La limitación es evidente: si necesitamos que distintas sucursales produzcan variantes propias de cada pizza, el if/elif termina explotando. Ese es exactamente el problema que resuelve Factory Method.
Info
El Simple Factory es útil como técnica de refactor cuando queremos aislar una serie de condicionales de creación, pero no ofrece extensibilidad vía herencia.
Factory Method
Note
El Factory Method define una interfaz para crear un objeto, pero delega en las subclases la decisión de qué clase concreta instanciar.
En lugar de tener una única clase factory que decide con condicionales, el Factory Method define un método abstracto de creación en la superclase. Cada subclase implementa ese método y devuelve el producto concreto que corresponda. La instanciación se difiere a las subclases.
classDiagram
class Creator {
<<abstract>>
+factory_method() Product
+operation()
}
class ConcreteCreatorA {
+factory_method() Product
}
class ConcreteCreatorB {
+factory_method() Product
}
class Product {
<<abstract>>
}
class ConcreteProductA
class ConcreteProductB
Creator <|-- ConcreteCreatorA
Creator <|-- ConcreteCreatorB
Product <|-- ConcreteProductA
Product <|-- ConcreteProductB
ConcreteCreatorA ..> ConcreteProductA : crea
ConcreteCreatorB ..> ConcreteProductB : crea
Consideremos un ejemplo canónico: una jerarquía de animales donde cada subclase decide qué instancia producir. La superclase define el flujo (show_animal) que consume el producto creado por el factory_method:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self) -> str: ...
@abstractmethod
def create_animal(self) -> "Animal": ...
def show_animal(self) -> None:
animal = self.create_animal()
print(f"El animal dice: {animal.make_sound()}")
class Dog(Animal):
def make_sound(self) -> str:
return "Guau!"
def create_animal(self) -> Animal:
return Dog()
class Cat(Animal):
def make_sound(self) -> str:
return "Miau!"
def create_animal(self) -> Animal:
return Cat()
Dog().show_animal() # El animal dice: Guau!
Cat().show_animal() # El animal dice: Miau!
El punto clave es que Animal.show_animal es agnóstico a la clase concreta: opera sobre la abstracción Animal y delega la instanciación a create_animal. Añadir un nuevo animal implica una nueva subclase, no modificar código existente — cumpliendo el principio abierto/cerrado.
Tip
Factory Method depende de herencia: cada subclase implementa el método de creación. Es ideal cuando la variación entre productos está atada a la variación de la clase creadora.
Abstract Factory
Mientras Factory Method crea un producto, el Abstract Factory crea familias completas de productos relacionados sin acoplar al cliente a las clases concretas de cada familia.
Un caso clásico: una aplicación que renderiza componentes de UI para distintos sistemas operativos. Botones y checkboxes de Windows deben usarse juntos, igual que los de macOS; mezclarlos rompe la coherencia visual. El Abstract Factory garantiza que solo se combinen componentes de la misma familia.
classDiagram
class GUIFactory {
<<abstract>>
+create_button() Button
+create_checkbox() Checkbox
}
class WindowsFactory
class MacFactory
class Button {
<<abstract>>
+render()
}
class Checkbox {
<<abstract>>
+render()
}
class WindowsButton
class WindowsCheckbox
class MacButton
class MacCheckbox
GUIFactory <|-- WindowsFactory
GUIFactory <|-- MacFactory
Button <|-- WindowsButton
Button <|-- MacButton
Checkbox <|-- WindowsCheckbox
Checkbox <|-- MacCheckbox
WindowsFactory ..> WindowsButton : crea
WindowsFactory ..> WindowsCheckbox : crea
MacFactory ..> MacButton : crea
MacFactory ..> MacCheckbox : crea
Implementación en Python:
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def render(self) -> None: ...
class Checkbox(ABC):
@abstractmethod
def render(self) -> None: ...
class WindowsButton(Button):
def render(self) -> None:
print("Renderizando botón de Windows")
class WindowsCheckbox(Checkbox):
def render(self) -> None:
print("Renderizando checkbox de Windows")
class MacButton(Button):
def render(self) -> None:
print("Renderizando botón de macOS")
class MacCheckbox(Checkbox):
def render(self) -> None:
print("Renderizando checkbox de macOS")
class GUIFactory(ABC):
@abstractmethod
def create_button(self) -> Button: ...
@abstractmethod
def create_checkbox(self) -> Checkbox: ...
class WindowsFactory(GUIFactory):
def create_button(self) -> Button:
return WindowsButton()
def create_checkbox(self) -> Checkbox:
return WindowsCheckbox()
class MacFactory(GUIFactory):
def create_button(self) -> Button:
return MacButton()
def create_checkbox(self) -> Checkbox:
return MacCheckbox()
class Application:
def __init__(self, factory: GUIFactory) -> None:
self.factory = factory
def create_ui(self) -> None:
button = self.factory.create_button()
checkbox = self.factory.create_checkbox()
button.render()
checkbox.render()
factory: GUIFactory = WindowsFactory() # o MacFactory()
Application(factory).create_ui()
Application depende exclusivamente de GUIFactory, Button y Checkbox — todas abstracciones. Cambiar de familia consiste en inyectar una factory distinta; el resto del código permanece intacto.
Factory Method vs Abstract Factory
Aunque comparten espíritu, no son intercambiables:
- Factory Method usa herencia: la subclase decide qué producto crear implementando un método.
- Abstract Factory usa composición: el cliente recibe una factory y llama a varios métodos de creación sobre ella, obteniendo una familia de productos coherentes.
- Factory Method escala en la dimensión de “un producto que varía”; Abstract Factory escala en la dimensión de “múltiples productos que varían de forma correlacionada”.
Static Factory
El Static Factory es una variante ligera que expone métodos de clase estáticos para construir instancias, en lugar de exponer constructores públicos. Es común en librerías del ecosistema Java y en APIs de Python que ofrecen métodos como datetime.now() o Path.home().
class Connection:
def __init__(self, dsn: str) -> None:
self._dsn = dsn
@classmethod
def from_env(cls) -> "Connection":
import os
return cls(dsn=os.environ["DATABASE_URL"])
@classmethod
def in_memory(cls) -> "Connection":
return cls(dsn="sqlite://:memory:")
Ventajas: los métodos estáticos pueden tener nombres semánticos (from_env, in_memory) que documentan la intención mucho mejor que un constructor sobrecargado. Limitación: no permite polimorfismo — no es reemplazable en tiempo de ejecución como sí lo son Factory Method o Abstract Factory.
Principio de Inversión de Dependencias
El Principio de Inversión de Dependencias (DIP, la “D” de SOLID) enuncia dos reglas:
- Los módulos de alto nivel no deben depender de módulos de bajo nivel. Ambos deben depender de abstracciones.
- Las abstracciones no deben depender de detalles. Los detalles deben depender de abstracciones.
Los patrones factory son una herramienta natural para aplicar DIP: al centralizar la creación en una abstracción, el módulo de alto nivel deja de instanciar clases concretas. Volviendo al ejemplo de la pizzería:
flowchart LR
subgraph Antes["Sin DIP"]
A1[PizzaStore] --> A2[CheesePizza]
A1 --> A3[VeggiePizza]
A1 --> A4[PepperoniPizza]
end
subgraph Despues["Con DIP + Factory"]
B1[PizzaStore] --> B2[Pizza abstracta]
B3[CheesePizza] --> B2
B4[VeggiePizza] --> B2
B5[PepperoniPizza] --> B2
end
En “Antes”, el flujo de dependencia va de alto a bajo nivel: PizzaStore conoce todas las pizzas concretas. En “Después”, ambos dependen de la abstracción Pizza: la dependencia queda invertida.
Un ejemplo aislado en Python que muestra el patrón:
from abc import ABC, abstractmethod
class MessageSender(ABC):
@abstractmethod
def send(self, message: str) -> None: ...
class EmailSender(MessageSender):
def send(self, message: str) -> None:
print(f"Enviando email: {message}")
class SmsSender(MessageSender):
def send(self, message: str) -> None:
print(f"Enviando SMS: {message}")
class NotificationService:
def __init__(self, sender: MessageSender) -> None:
self._sender = sender
def notify(self, message: str) -> None:
self._sender.send(message)
NotificationService(EmailSender()).notify("Nuevo despliegue exitoso")
NotificationService no conoce EmailSender ni SmsSender; solo la abstracción MessageSender. Un factory puede alimentar esa dependencia según configuración, entorno o feature flags, sin tocar NotificationService.
Consideraciones
- Todos los factories encapsulan la creación de objetos y reducen el acoplamiento a implementaciones concretas.
- Simple Factory no es un patrón GoF; es un idiom útil para aislar condicionales de creación en un único lugar.
- Factory Method depende de herencia: cada subclase implementa el método de creación y decide el producto concreto.
- Abstract Factory depende de composición: el cliente recibe una factory y obtiene familias de productos coherentes.
- Los tres refuerzan el Principio de Inversión de Dependencias al hacer que el código cliente dependa de abstracciones, no de tipos concretos.
- El DIP es una guía transversal, no un patrón: aplica siempre que quieras evitar el acoplamiento con implementaciones específicas.
- Factory es una técnica de diseño, no una clase específica. Su nombre puede variar (
build,create,from_x), lo importante es la intención: encapsular la construcción de objetos.
Note
🚀 Elige Simple Factory para aislar condicionales, Factory Method cuando la variación está atada a la jerarquía del creador, y Abstract Factory cuando necesitas coherencia entre múltiples productos relacionados.
Continúa la serie
Si te interesa seguir explorando patrones de diseño, revisa los otros artículos de la serie:


