Accueil / Tutoriels / Factory

Factory

Publié le 3 Mars 2025
Conception

Factory est un pattern de création, qui permet de créer des objets sans spécifier la classe exacte de l’objet à instancier.

Principe

L’objectif est de déléguer la création d’objets à une méthode ou à une classe spécialisée ce qui permet de découpler la création de l’objet de sa fonction principale et de rendre le code plus évolutif. En général, on définit une interface pour la création de l’objet et ce sont les classes enfants qui vont décider quel type d’objet instancier.

Exemples d’utilisations

Envoi de notifications à des utilisateurs

Une application peut par exemple envoyer des notifications via plusieurs canaux à ses utilisateurs (Email, SMS, etc…). Le pattern Factory peut centraliser la création dynamique des différents objets liés à la notification.

Moyens de paiements sur un site de e-commerce

Sur une page de paiement, on a souvent différents moyens de paiements disponibles. Grâce à une factory, il est possible de centraliser cette logique de paiement en fonction du moyen de paiement et/ou du prestataire sélectionné.

Points d’attentions

Dans des applications de petite taille ou des usages simples, l’ajout d’une factory peut s’avérer excessif. Si l’application n’a pas besoin d’une grande flexibilité dans la création d’objets, la factory peut rendre le code abstrait sans apporter de réels bénéfices.

La logique de création des objets est déplacée dans une classe dédiée, ce qui peut rendre difficile la lecture du code, notamment lors des débogages ou d’une modification du code.

Dans des cas où la création d’objets est très fréquente, l’ajout d’une couche d’abstraction peut générer une légère baisse des performances.

Implémenter une factory

On crée une interface ou une classe abstraite. Les classes concrètes implémentent ensuite l’interface ou la classe abstraite et représentent un type d’objet à créer.

On met en place une classe (qu’on appelle le plus souvent Factory) qui contient une ou plusieurs méthodes pour la création d’objets. Ces méthodes sont souvent statiques (ce n’est pas une obligation) et vont prendre en paramètre les informations qui permettront de définir quel classe il faudra instancier.

Au niveau de notre application, plutôt que d’instancier directement une classe, on va appeler une des méthodes de notre classe Factory qui se chargera ensuite de créer le bon objet.

Exemple d'utilisation de Factory avec Go

Voici un exemple en Go :



package factory

type Notification interface {
	Send(message string)
}


package factory

import "fmt"

type EmailNotification struct{}

func (e EmailNotification) Send(message string) {
	// Code pour l'envoi d'email
	fmt.Println("Email envoyé :", message)
}


package factory

import "fmt"

type SMSNotification struct{}

func (s SMSNotification) Send(message string) {
	// Code pour l'envoi de SMS
	fmt.Println("SMS envoyé :", message)
}


package factory

import (
	"errors"
	"strings"
)

func CreateNotification(notificationType string) (Notification, error) {
	switch strings.ToLower(notificationType) {
	case "email":
		return EmailNotification{}, nil
	case "sms":
		return SMSNotification{}, nil
	default:
		return nil, errors.New("type de notification non supporté : " + notificationType)
	}
}


package main

import (
	"fmt"
	"practice/designpatterns/factory-decorticode/factory"
)

func main() {
	notification, err := factory.CreateNotification("email")
	if err != nil {
		fmt.Println(err)
		return
	}
	notification.Send("Envoi du message")
}

Le même exemple en PHP

Voici exactement le même exemple mais avec PHP :


namespace Practice\DesignPatterns\Factory;

interface NotificationInterface
{
    public function send(string $message);
}


namespace Practice\DesignPatterns\Factory;

class EmailNotification implements NotificationInterface {
    public function send(string $message) {
        // Code pour l'envoi d'emails
        echo "Email envoyé : $message";
    }
}


namespace Practice\DesignPatterns\Factory;

class SMSNotification implements NotificationInterface {
    public function send(string $message) {
        // Code pour l'envoi de SMS
        echo "SMS envoyé : $message";
    }
}


namespace Practice\DesignPatterns\Factory;

use Exception;

class NotificationFactory {
    public static function createNotification(string $type): NotificationInterface {
        switch (strtolower($type)) {
            case 'email':
                return new EmailNotification();
            case 'sms':
                return new SMSNotification();
            default:
                throw new Exception("Type de notification non supporté : $type");
        }
    }
}


declare(strict_types=1);

use Practice\DesignPatterns\NotificationFactory;

require "./vendor/autoload.php";

$notification = NotificationFactory::createNotification('email');
$notification->send("Envoi du message");

Conclusion

J'espère que grâce à cet article vous êtes désormais plus à l'aise avec le design pattern Factory. Vous pouvez retrouver mon article sur les design patterns ou les autres tutoriels sur Observer, Chain of responsibility et Decorator.