Factory (ou fabrique en français)
Le Design Pattern (DP) Factory, aussi appelé Factory Method, est un patron de conception de type créationnel. Son but est de déléguer la création d'objets à des sous-classes, plutôt que de l'effectuer directement dans le code client.
Problème que le Factory Method résout
La création d'objets dépend fortement d'implémentations concrètes. Cela rend le code moins flexible et moins maintenable si l'on veut changer la classe instanciée plus tard.
Exemple
Une application de gestion de documents qui doit créer différents types (PDF, Word, HTML) selon un paramètre fourni.
Naïvement, le code ressemblerait à cela :
def main():
type_document = "pdf"
nom_fichier = "rapport_projet"
# Création du document selon le type
if type_document == "pdf":
doc = PDFDocument(nom_fichier)
elif type_document == "word":
doc = WordDocument(nom_fichier)
elif type_document == "html"
doc = HTMLDocument(nom_fichier)
else:
doc = Document(nom_fichier)
# Utilisation du document
doc.ouvrir()
if __name__ = "__main__":
main()
On peut alors identifier plusieurs problèmes :
- Violation du principe ouvert/fermé : Si on veut ajouter un nouveau type de document, nous devons modifier la fonction
main()et ajouter une nouvelle condition. - Duplication du code : Le code de création d'un document sera répliqué à chaque endroit ou l'on veut créer un document.
- Difficile à maintenir : Plus on gérera d'extension de fichier et plus il sera difficle de maintenir ce code.
- Manque de flexibilité : Les paramètres de création pourraient devenir plus complexes avec le temps.
Dans ce cas, l'utilisation du patron de conception Factory permettrait de centraliser la logique de création des objets, de découpler le code client des implémentations concrètes, de faciliter l'ajout de nouveaux types sans modifier le code existant, et d'encapsuler une logique de création potentiellement complexe.
Diagramme UML
Code
from abc import ABC, abstractmethod
# Produit abstrait
class Document(ABC):
@abstractmethod
def export(self, content: str):
pass
# Produits concrets
class WordDocument(Document):
def export(self, content: str):
print(f"Exporting Word document with content:\n{content}")
class PDFDocument(Document):
def export(self, content: str):
print(f"Exporting PDF document with content:\n{content}")
class HTMLDocument(Document):
def export(self, content: str):
print(f"Exporting HTML document with content:\n<html><body>{content}</body></html>")
# Factory
class DocumentFactory:
@staticmethod
def create_document(doc_type: str) -> Document:
doc_type = doc_type.lower()
if doc_type == "word":
return WordDocument()
elif doc_type == "pdf":
return PDFDocument()
elif doc_type == "html":
return HTMLDocument()
else:
raise ValueError(f"Unknown document type: {doc_type}")
# --- Utilisation ---
if __name__ == "__main__":
doc_type = "pdf" # peut être "word", "pdf" ou "html"
factory = DocumentFactory()
document = factory.create_document(doc_type)
document.export("Voici le contenu du document.")