Introducció

El patró Factory Method és un patró de disseny creacional que proporciona una interfície per crear objectes en una superclasse, però permet que les subclasses alterin el tipus d'objectes que es crearan. Aquest patró és útil quan la creació de l'objecte implica una lògica complexa o quan el tipus d'objecte a crear no es coneix fins al moment de l'execució.

Objectius del Patró Factory Method

  1. Encapsular la Creació d'Objectes: Permet encapsular la lògica de creació d'objectes dins d'un mètode, fent que el codi sigui més modular i fàcil de mantenir.
  2. Flexibilitat: Facilita la substitució de subclasses sense modificar el codi existent.
  3. Reduir la Dependència: Minimitza la dependència entre les classes, promovent un disseny més desacoblat.

Estructura del Patró Factory Method

El patró Factory Method consta de les següents parts:

  1. Producte: Defineix la interfície dels objectes que la fàbrica crearà.
  2. Producte Concret: Implementa la interfície del producte.
  3. Creador: Declara el mètode de fàbrica que retorna un objecte de tipus Producte.
  4. Creador Concret: Implementa el mètode de fàbrica per crear un objecte de Producte Concret.

Diagrama UML

+------------------+       +------------------+
|      Creator     |       |    ConcreteCreator|
+------------------+       +------------------+
| + factoryMethod()|<------| + factoryMethod() |
+------------------+       +------------------+
         ^                          ^
         |                          |
         |                          |
+------------------+       +------------------+
|     Product      |       |  ConcreteProduct |
+------------------+       +------------------+
| + operation()    |       | + operation()    |
+------------------+       +------------------+

Exemple Pràctic

A continuació, es presenta un exemple pràctic del patró Factory Method en Python:

Interfície del Producte

from abc import ABC, abstractmethod

class Transport(ABC):
    @abstractmethod
    def deliver(self) -> str:
        pass

Productes Concrets

class Truck(Transport):
    def deliver(self) -> str:
        return "Deliver by land in a box"

class Ship(Transport):
    def deliver(self) -> str:
        return "Deliver by sea in a container"

Creador

class Logistics(ABC):
    @abstractmethod
    def create_transport(self) -> Transport:
        pass

    def plan_delivery(self) -> str:
        transport = self.create_transport()
        return transport.deliver()

Creadors Concrets

class RoadLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Truck()

class SeaLogistics(Logistics):
    def create_transport(self) -> Transport:
        return Ship()

Client

def client_code(logistics: Logistics) -> None:
    print(f"Client: {logistics.plan_delivery()}")

if __name__ == "__main__":
    print("App: Launched with the RoadLogistics.")
    client_code(RoadLogistics())

    print("\nApp: Launched with the SeaLogistics.")
    client_code(SeaLogistics())

Explicació del Codi

  1. Interfície del Producte: Transport és una classe abstracta que defineix el mètode deliver.
  2. Productes Concrets: Truck i Ship són implementacions concretes de Transport.
  3. Creador: Logistics és una classe abstracta que declara el mètode de fàbrica create_transport i un altre mètode plan_delivery que utilitza el producte creat.
  4. Creadors Concrets: RoadLogistics i SeaLogistics implementen el mètode de fàbrica per crear instàncies de Truck i Ship, respectivament.
  5. Client: El client utilitza el creador concret per planificar la entrega.

Exercici Pràctic

Enunciat

Implementa un sistema de notificacions que utilitzi el patró Factory Method. El sistema ha de poder enviar notificacions per correu electrònic i per SMS.

Solució

Interfície del Producte

from abc import ABC, abstractmethod

class Notification(ABC):
    @abstractmethod
    def send(self, message: str) -> None:
        pass

Productes Concrets

class EmailNotification(Notification):
    def send(self, message: str) -> None:
        print(f"Sending email with message: {message}")

class SMSNotification(Notification):
    def send(self, message: str) -> None:
        print(f"Sending SMS with message: {message}")

Creador

class NotificationFactory(ABC):
    @abstractmethod
    def create_notification(self) -> Notification:
        pass

    def notify(self, message: str) -> None:
        notification = self.create_notification()
        notification.send(message)

Creadors Concrets

class EmailNotificationFactory(NotificationFactory):
    def create_notification(self) -> Notification:
        return EmailNotification()

class SMSNotificationFactory(NotificationFactory):
    def create_notification(self) -> Notification:
        return SMSNotification()

Client

def client_code(factory: NotificationFactory, message: str) -> None:
    factory.notify(message)

if __name__ == "__main__":
    print("App: Launched with the EmailNotificationFactory.")
    client_code(EmailNotificationFactory(), "Hello via Email!")

    print("\nApp: Launched with the SMSNotificationFactory.")
    client_code(SMSNotificationFactory(), "Hello via SMS!")

Explicació del Codi

  1. Interfície del Producte: Notification és una classe abstracta que defineix el mètode send.
  2. Productes Concrets: EmailNotification i SMSNotification són implementacions concretes de Notification.
  3. Creador: NotificationFactory és una classe abstracta que declara el mètode de fàbrica create_notification i un altre mètode notify que utilitza el producte creat.
  4. Creadors Concrets: EmailNotificationFactory i SMSNotificationFactory implementen el mètode de fàbrica per crear instàncies de EmailNotification i SMSNotification, respectivament.
  5. Client: El client utilitza el creador concret per enviar notificacions.

Resum

El patró Factory Method és una tècnica poderosa per encapsular la creació d'objectes, proporcionant flexibilitat i reduint la dependència entre classes. En aquest tema, hem vist la seva estructura, un exemple pràctic i un exercici per reforçar els conceptes apresos. Amb aquest patró, podem crear sistemes més modulars i fàcils de mantenir.

© Copyright 2024. Tots els drets reservats