Cuando una aplicación crece y necesita producir distintos tipos de objetos, el acoplamiento se convuelve un problema serio. El patrón Factory ofrece una solución elegante: delegar la creación de objetos a métodos especializados que respetan una interfaz común, permitiendo agregar nuevos productos sin modificar el código existente. A continuación se desglosan las ideas centrales de este patrón creacional y cómo se aplica paso a paso.
¿Qué es el patrón Factory y por qué forma parte de los patrones creacionales?
Dentro de la familia de patrones de diseño creacionales existe un grupo que comparte una misma filosofía: los patrones factory. Su nombre lo dice todo: se trata de fábricas cuya responsabilidad es crear objetos (productos) de manera controlada [0:26].
El patrón Factory provee una interfaz para crear objetos basados en una superclase, posibilitando que las subclases creadoras alteren el tipo de objeto que retornan en su proceso de fabricación [0:48]. Esto implica polimorfismo: distintas fábricas comparten un comportamiento común, pero cada una decide internamente qué producto concreto construir.
¿Cómo se llega a necesitar Factory en un proyecto real?
Para entender la necesidad, vale la pena seguir un caso práctico de fabricación de coches [1:29].
¿Qué sucede cuando todo el código está acoplado a un solo modelo?
- Se crea una aplicación que maneja la producción de coches.
- La primera versión solo contempla el modelo Mastodon.
- Todo el código de fabricación, costos y demás features importa y utiliza directamente la clase
MastodonCar [1:38].
Cuando la app tiene éxito y se solicita un nuevo modelo, el Rhino, aparece el problema: si todos los archivos dependen de Mastodon, agregar Rhino obliga a refactorizar una enorme cantidad de código [1:55].
Una solución rápida pero frágil sería insertar condicionales por todos lados: "si quieres Mastodon, devuelve Mastodon; si quieres Rhino, devuelve Rhino" [2:24]. Esto genera código difícil de mantener y escalar.
¿Qué solución propone el patrón Factory?
El patrón sugiere sustituir el uso directo del operador new por un método fábrica que se encargue de la creación de los objetos [2:46]. Los pasos clave son:
- Método fábrica en lugar de
new directo: en vez de instanciar new MastodonCar() o new RhinoCar(), se llama a una función que recibe qué producto crear y lo devuelve [2:55].
- Internamente se sigue usando
new: cada subclase fábrica (por ejemplo MastodonFactory o RhinoFactory) utiliza new dentro de su implementación, pero ese detalle queda encapsulado [3:13].
- Superclase o interfaz fábrica común: todas las fábricas están basadas en una clase o interfaz compartida que dicta el comportamiento obligatorio, como un método
create o produce [3:28]. Esto permite intercambiar fábricas sin afectar al resto del sistema.
¿Cómo se relacionan los productos con una clase base?
Los productos retornados por las fábricas también deben seguir una clase base o interfaz de producto [3:58]. Si Mastodon y Rhino implementan la interfaz BaseCar —por ejemplo, ambos exponen un método showCost()—, el método fábrica puede declarar que retorna un BaseCar sin importar cuál sea el coche concreto [4:07].
Esto conecta directamente con el concepto de contratos e interfaces visto en la introducción a patrones de diseño: así como un RESTGateway y un GraphQLGateway pueden intercambiarse si ambos implementan el contrato Gateway, un Mastodon y un Rhino son intercambiables si ambos cumplen con BaseCar [4:27].
Las ventajas de este enfoque son claras:
- Desacoplamiento: el código consumidor no conoce la clase concreta del producto.
- Extensibilidad: agregar un tercer modelo solo requiere crear una nueva subclase fábrica y una nueva clase producto, sin tocar el código existente.
- Polimorfismo real: se puede cambiar de
MastodonFactory a RhinoFactory en tiempo de ejecución sin romper nada [4:55].
Si te interesa profundizar en cómo luce este patrón a nivel de diagrama y código, comparte tu experiencia o dudas sobre cómo has manejado la creación de objetos en tus proyectos.