Lección 8.3 : Patron de diseño Factory Method
Patrón de Diseño Factory Method en Python
Introducción
¡Hola a todos! Soy Yuscu Mejía y en esta lección vamos a explorar el concepto del patrón de diseño Factory Method en Python. El patrón Factory Method proporciona una interfaz para crear objetos en una clase padre, pero permite a las subclases alterar el tipo de objetos que se crearán.
Características
El patrón Factory Method en Python tiene las siguientes características:
- Define una interfaz para crear un objeto, pero permite a las subclases decidir qué clase instanciar.
- Promueve la reutilización del código y la separación de responsabilidades.
- Facilita la incorporación de nuevas clases de productos sin modificar el código existente.
Propósito
El patrón de diseño Factory Method permite definir una interfaz para la creación de objetos, pero deja que las subclases decidan qué clase instanciar. Permite que una clase delegue la responsabilidad de creación de objetos a sus subclases.
Problema
El problema que resuelve el patrón Factory Method es el de permitir a una clase diferir la instanciación a subclases específicas, facilitando la extensión y el mantenimiento del código al evitar dependencias directas entre la clase creadora y las clases de los objetos creados.
Solución
La solución propuesta por el patrón Factory Method es utilizar un método de fábrica para crear objetos. Las subclases sobrescriben este método para crear instancias de productos específicos.
Analogía en el Mundo Real
Una analogía del mundo real sería una pastelería. Dependiendo del tipo de pedido (tarta, pastel, cupcake), la pastelería utiliza una receta específica para crear el producto. El método para crear el producto es el mismo, pero el resultado varía según la receta utilizada.
Estructura
La estructura del patrón Factory Method incluye los siguientes componentes:
- Product: Interfaz común para todos los productos creados por la fábrica.
- ConcreteProduct: Implementaciones concretas de la interfaz Product.
- Creator: Clase que declara el método de fábrica.
- ConcreteCreator: Subclases que sobrescriben el método de fábrica para crear instancias de productos específicos.

Aplicabilidad
El patrón Factory Method es aplicable cuando:
- Una clase no puede anticipar el tipo de objetos que debe crear.
- Una clase quiere que sus subclases especifiquen los objetos que crea.
- Se desea delegar la responsabilidad de creación a subclases para promover la reutilización del código y la flexibilidad.
Pros y Contras
- Pros:
- Permite a una clase delegar la creación de objetos a sus subclases.
- Promueve la reutilización del código al encapsular la lógica de creación en métodos de fábrica.
- Facilita la incorporación de nuevas clases de productos sin modificar el código existente.
- Contras:
- Introduce complejidad adicional debido a la creación de múltiples subclases y métodos de fábrica.
- Puede ser menos eficiente si se crean muchos objetos de manera repetitiva.
Vamos a ver el uso del Patrón Factory Method
A continuación, un ejemplo de cómo utilizar el patrón Factory Method en Python, presentado por Yuscu Mejía:
Esta implementación demuestra cómo utilizar el patrón de diseño Factory Method para crear y gestionar diferentes tipos de documentos, encapsulando la lógica de creación y operación específica para cada tipo de documento.
- Patrón Factory Method:
# Clase Base para el Documento
class Documento(ABC):
@abstractmethod
def crear(self):
pass
@abstractmethod
def abrir(self):
pass
@abstractmethod
def cerrar(self):
pass
# Clases para los Tipos de Documentos
class DocumentoTexto(Documento):
def crear(self):
print("Creando un documento de texto...")
def abrir(self):
print("Abriendo un documento de texto...")
def cerrar(self):
print("Cerrando un documento de texto...")
class DocumentoPDF(Documento):
def crear(self):
print("Creando un documento PDF...")
def abrir(self):
print("Abriendo un documento PDF...")
def cerrar(self):
print("Cerrando un documento PDF...")
class DocumentoImagen(Documento):
def crear(self):
print("Creando un documento de imagen...")
def abrir(self):
print("Abriendo un documento de imagen...")
def cerrar(self):
print("Cerrando un documento de imagen...")
# Clase Factory para Crear Documentos
from abc import ABC, abstractmethod
class DocumentoFactory(ABC):
@abstractmethod
def crear_documento(self):
pass
class TextoFactory(DocumentoFactory):
def crear_documento(self):
return DocumentoTexto()
class PDFFactory(DocumentoFactory):
def crear_documento(self):
return DocumentoPDF()
class ImagenFactory(DocumentoFactory):
def crear_documento(self):
return DocumentoImagen()
# Clase Principal
def gestionar_documento(factory: DocumentoFactory):
documento = factory.crear_documento()
documento.crear()
documento.abrir()
documento.cerrar()
if __name__ == "__main__":
# Crear y gestionar un documento de texto
print("Gestión de Documento de Texto:")
gestionar_documento(TextoFactory())
# Crear y gestionar un documento PDF
print("\nGestión de Documento PDF:")
gestionar_documento(PDFFactory())
# Crear y gestionar un documento de imagen
print("\nGestión de Documento de Imagen:")
gestionar_documento(ImagenFactory())
Ventajas del Patrón Factory Method
-
Variación en los tipos de objetos creados:
El sistema necesita crear diferentes tipos de documentos (Texto, PDF, Imagen), cada uno con su propio comportamiento específico.
El patrón Factory Method permite la creación de objetos de una jerarquía de clases sin acoplar el código cliente a las clases concretas. -
Extensibilidad:
Si en el futuro se agregan nuevos tipos de documentos, como DocumentoAudio o DocumentoVideo, se pueden crear nuevas fábricas específicas sin modificar el código existente.
Este patrón facilita la extensibilidad al permitir la adición de nuevos tipos de productos sin cambiar el código cliente que utiliza la fábrica. -
Separación de la lógica de creación:
El patrón Factory Method separa la lógica de creación del objeto de su uso.
Esto hace que el código sea más limpio y más fácil de mantener, ya que la responsabilidad de crear instancias específicas está aislada en las fábricas. -
Principio de responsabilidad única:
Cada fábrica se encarga de crear un tipo específico de documento.
Esto sigue el principio de responsabilidad única, donde cada clase tiene una sola responsabilidad. -
Cumplimiento del principio de inversión de dependencias:
Al depender de abstracciones (interfaces o clases abstractas) en lugar de clases concretas, el código cliente se vuelve más flexible y menos propenso a cambios en las implementaciones concretas de los documentos.
Programación sin las clase factory
def gestionar_documento(documento):
documento.crear()
documento.abrir()
documento.cerrar()
if __name__ == "__main__":
# Crear y gestionar un documento de texto
print("Gestión de Documento de Texto:")
documento_texto = DocumentoTexto()
gestionar_documento(documento_texto)
# Crear y gestionar un documento PDF
print("\nGestión de Documento PDF:")
documento_pdf = DocumentoPDF()
gestionar_documento(documento_pdf)
# Crear y gestionar un documento de imagen
print("\nGestión de Documento de Imagen:")
documento_imagen = DocumentoImagen()
gestionar_documento(documento_imagen)
Diferencias Clave y Ventajas del Factory Method
Modularidad:
- Sin Factory Method: El código cliente contiene directamente la lógica de creación de cada tipo de documento.
- Con Factory Method: La lógica de creación está encapsulada en fábricas específicas. El código cliente no necesita saber cómo se crea cada tipo de documento, solo necesita saber qué fábrica utilizar.
Desacoplamiento:
- Sin Factory Method: El código cliente está fuertemente acoplado a las clases concretas de los documentos.
- Con Factory Method: El código cliente depende de fábricas abstractas y utiliza fábricas específicas para crear documentos. Esto reduce el acoplamiento y hace el código más flexible.
Extensibilidad:
- Sin Factory Method Añadir un nuevo tipo de documento implica modificar el código cliente en varios lugares.
- Con Factory Method: Añadir un nuevo tipo de documento implica crear una nueva fábrica y modificar el código cliente en un lugar específico (generalmente en una única línea de código).
Práctica
Para practicar, les invito a ver nuestro tutorial en video sobre el patrón de diseño Factory Method en Python, presentado por Yuscu Mejía:
Recorda si te gusta los videos, te agradeceria si le pones un comentario o un like para saber si subir mas videos! 😮
Si no sabes que comentar, comenta con: estoy avanzando rapido con el curso de Programacion python 🙂 asi te detectaremos que viniste de aca, para una estadistica si conviene o no subir videos

Ejercicio
Ahora les propongo un ejercicio para aplicar lo que hemos aprendido sobre el patrón de diseño Factory Method en Python, con la guía de Yuscu Mejía:
Ejercicio: Implementación del Patrón Factory Method
En este ejercicio, vamos a crear una clase llamada Dialogo que pueda utilizar diferentes métodos de fábrica para crear botones. Implementaremos dos tipos de botones: HTMLButton y WindowsButton.
Sigue estos pasos para completar el ejercicio:
- Define una interfaz
Buttoncon un métodorender. - Crea dos clases que implementen la interfaz
Button:HTMLButtonyWindowsButton. - Define una clase
Dialogoque declare un método de fábricacrear_boton. - Crea dos subclases de
Dialogo:WebDialogoyWindowsDialogo, que sobrescriban el método de fábrica para crear botones específicos. - Implementa el método
renderen cada clase de botón para simular el dibujo del botón en pantalla.
Veamos cómo Yuscu Mejía implementaría la solución a este ejercicio:
#Ejercicio Resuelto
# Definir la interfaz Button
class Button:
def render(self):
pass
# Definir los botones concretos
class HTMLButton(Button):
def render(self):
return "Renderizar un botón HTML."
class WindowsButton(Button):
def render(self):
return "Renderizar un botón de Windows."
# Definir la clase Dialogo
class Dialogo:
def crear_boton(self):
pass
def render(self):
boton = self.crear_boton()
resultado = f"Dialogo: {boton.render()}"
return resultado
# Definir dialogos concretos
class WebDialogo(Dialogo):
def crear_boton(self):
return HTMLButton()
class WindowsDialogo(Dialogo):
def crear_boton(self):
return WindowsButton()
# Ejemplo de uso
def client_code(dialogo: Dialogo):
print(dialogo.render())
print("App: Ejecutado con WebDialogo")
client_code(WebDialogo())
print("App: Ejecutado con WindowsDialogo")
client_code(WindowsDialogo())

