Samuel KAMDOUM FOLONG

Samuel KAMDOUM FOLONG

Author

12
7
0

Le Design Pattern Factory : Simplifiez la Creation d'Objets dans vos Applications

Le Design Pattern Factory est l'un des patrons de conception les plus populaires en programmation orientee objet. Il permet de centraliser la creation d'objets, rendant le code plus lisible, modulaire et maintenable.

Le Design Pattern Factory : Simplifiez la Creation d'Objets dans vos Applications

Un Design Pattern en francais Patron de Conception est une solution generale, reutilisable et eprouvee pour resoudre des problemes recurrents dans le developpement logiciel. Il decrit une maniere eprouvee et optimale d'organiser le code pour repondre a des besoins specifiques tout en respectant les principes de conception comme la modularite, la reutilisabilite et le faible couplage.

Bon a savoir!

Les design patterns ne sont pas des implementations concretes, mais des concepts abstraits qui servent de guide pour structurer le code. Ils permettent aux developpeurs de resoudre des problemes frequents avec des solutions eprouvees, de rendre le code plus comprehensible, et de faciliter la maintenance ainsi que la collaboration au sein d'une equipe. Ils sont organises en trois (03) categories :

  1. Les patrons de creation
  2. Les patrons structurels
  3. Les patrons comportementaux

Dans ce tutoriel, nous allons nous interesser a un patron de conception de la categorie creation : Factory.

# Qu'est-ce que le patron de conception (design pattern) Factory ?

Le patron de conception Factory est l'un des patrons de conception les plus populaires en programmation orientee objet. Il permet de centraliser la creation d'objets, rendant le code plus lisible, modulaire et maintenable. Ce pattern repose sur le principe de delegation : au lieu d'instancier directement des objets, vous confiez cette tache a une classe dediee, appelee la "Factory".

Grace a ce mecanisme, le code client n'a pas besoin de connaitre les details de l'instanciation des objets, ce qui favorise un faible couplage. En consequence, si les types d'objets a creer evoluent ou necessitent des changements, vous n'aurez qu'a modifier la Factory sans impacter le reste du code.

# Pourquoi utiliser le design pattern Factory ?

Le design pattern Factory est une solution puissante pour simplifier et centraliser la creation d'objets dans une application. En isolant cette logique dans une classe dediee, il permet de reduire le couplage entre le code client et les classes concretes, rendant ainsi le code plus modulaire et facile a maintenir. Cela est particulierement utile lorsque les objets necessitent des configurations complexes ou lorsque plusieurs types d'objets doivent etre instancies dynamiquement en fonction de la logique metier.

Ce pattern favorise egalement l'extensibilite et la testabilite du code. En cas d'ajout ou de modification de types d'objets, seule la Factory doit etre mise a jour, respectant le principe ouvert/ferme. De plus, en encapsulant la logique conditionnelle et en standardisant le processus d'instanciation, il garantit une structure claire et coherente, ideale pour des systemes evolutifs et robustes.

# Exemple d'implementation

Imaginons que nous gerons un restaurant proposant un service de livraison rapide pour satisfaire nos clients. Nos moyens de transport sont varies afin de repondre a des besoins specifiques : velo, moto et voiture. Pour gerer cela, notre restaurant doit decider dynamiquement du moyen de transport a utiliser en fonction des caracteristiques de la livraison (distance, poids des commandes, type de zone, etc.).

Implementation sans le patron de conception Factory
// Interface de base pour les moyens de livraison
public interface Delivery {
    void deliver(String packageDetails);
}

// Classes concretes pour chaque type de livraison
public class BikeDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par velo : " + packageDetails);
    }
}

public class MotoDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par moto : " + packageDetails);
    }
}

// Classe principale qui decide du moyen de livraison
public class DeliveryService {
    public void processDelivery(String type, String packageDetails) {
        Delivery delivery;
        if (type.equals("bike")) {
            delivery = new BikeDelivery();
        } else if (type.equals("moto")) {
            delivery = new MotoDelivery();
        } else {
            throw new IllegalArgumentException("Type de livraison inconnu");
        }
        delivery.deliver(packageDetails);
    }
}

Problemes dans cette implementation

  1. Couplage eleve : La classe DeliveryService est fortement couplee aux classes specifiques de livraison (BikeDelivery et MotoDelivery). Ajouter un nouveau type de livraison necessite de modifier la logique dans DeliveryService, ce qui viole le principe ouvert/ferme (Open/Close principle) du principe SOLID.
  2. Complexite accrue : Imaginons que le restaurant devienne de plus en plus sollicite et doive ajouter d'autres moyens de livraison tels que les voitures pour les grandes quantites de commandes et des drones pour des livraisons express. La logique conditionnelle (if-else) devient rapidement difficile a gerer au fur et a mesure que le nombre de moyens de livraison augmente. Nous pouvons voir le code suivant:
  3. Testabilite limitee : Il est difficile de tester chaque scenario de livraison individuellement sans dependre directement des classes concretes.
// Interface de base pour les moyens de livraison
public interface Delivery {
    void deliver(String packageDetails);
}

// Classes concretes pour chaque type de livraison
public class BikeDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par velo : " + packageDetails);
    }
}

public class CarDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par voiture : " + packageDetails);
    }
}

public class MotoDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par moto : " + packageDetails);
    }
}

public class DroneDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par drone : " + packageDetails);
    }
}

// Classe principale qui decide du moyen de livraison
public class DeliveryService {
    public void processDelivery(String type, String packageDetails) {
        Delivery delivery;
        if (type.equals("bike")) {
            delivery = new BikeDelivery();
        } else if (type.equals("car")) {
            delivery = new CarDelivery();
        } else if (type.equals("moto")) {
            delivery = new MotoDelivery();
        } else if (type.equals("drone")) {
            delivery = new DroneDelivery();
        } else {
            throw new IllegalArgumentException("Type de livraison inconnu");
        }
        delivery.deliver(packageDetails);
    }
}
Implementation avec le patron de conception Factory

Avec le design patron de conception Factory, nous centralisons la creation des objets dans la classe DeliveryFactory

// Interface de base pour les moyens de livraison
public interface Delivery {
    void deliver(String packageDetails);
}

// Classes concretes pour chaque type de livraison
public class BikeDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par velo : " + packageDetails);
    }
}

public class CarDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par voiture : " + packageDetails);
    }
}

public class MotoDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par moto : " + packageDetails);
    }
}

public class DroneDelivery implements Delivery {
    public void deliver(String packageDetails) {
        System.out.println("Livraison par drone : " + packageDetails);
    }
}

// Factory pour creer les objets Delivery
public class DeliveryFactory {
    public static Delivery getDelivery(String type) {
        switch (type.toLowerCase()) {
            case "bike": return new BikeDelivery();
            case "car": return new CarDelivery();
            case "moto": return new MotoDelivery();
            case "drone": return new DroneDelivery();
            default: throw new IllegalArgumentException("Type de livraison inconnu");
        }
    }
}

// Classe principale qui utilise la Factory
public class DeliveryService {
    public void processDelivery(String type, String packageDetails) {
        Delivery delivery = DeliveryFactory.getDelivery(type);
        delivery.deliver(packageDetails);
    }
}

Les deux implementations peuvent sembler similaires au premier abord, car dans les deux cas, nous avons une logique de selection pour decider quel objet creer. Cependant, la principale difference reside dans l'emplacement de cette logique et dans ses implications pour la modularite, la maintenabilite et l'extensibilite.

Explications

  1. Faible couplage : La classe DeliveryService n'a plus besoin de connaitre les details des classes concretes. Elle delegue cette responsabilite a la DeliveryFactory. Cela libere DeliveryService de la responsabilite de savoir "comment" instancier les objets, ce qui respecte le Principe de Responsabilite Unique ou Single Responsability Principle (SRP).
  2. Extensibilite : Ajouter un nouveau type de livraison (par exemple, "livraison par bateau") ne necessite qu'une modification dans la DeliveryFactory. Aucune modification du code client (comme DeliveryService) n'est requise, ce qui respecte le principe ouvert/ferme (Open/Close principle).
  3. Maintenance simplifiee : La logique de creation est centralisee dans une seule classe, rendant le code plus lisible et plus facile a gerer.
  4. Testabilite amelioree : La DeliveryFactory peut etre testee independamment pour verifier qu'elle retourne les bons objets, et des objets simules peuvent etre injectes dans les tests.

Le design pattern Factory est une solution elegante et efficace pour simplifier et centraliser la creation d'objets dans des systemes complexes comme notre exemple de livraison. En deleguant la responsabilite de l'instanciation a une Fabrique, nous avons pu reduire le couplage entre les composants, ameliorer la modularite du code, et faciliter son extensibilite. Cela permet de repondre rapidement aux besoins evolutifs, comme l'ajout de nouveaux moyens de transport, sans impacter le reste du systeme. En suivant ce modele, le code devient plus clair, plus maintenable et plus adapte aux projets de grande envergure.

En comparaison avec l'approche classique, l'utilisation du design pattern Factory demontre ses avantages dans des contextes necessitant une forte evolutivite. Que ce soit pour des applications de livraison, de gestion de paiements, ou d'autres systemes dynamiques, ce pattern est un outil incontournable pour tout developpeur souhaitant concevoir des logiciels robustes et bien structures. En adoptant de tels principes, vous vous assurez de creer des applications pretes a evoluer avec les besoins de vos utilisateurs.

Nous voila arrives a la fin de ce tutoriel! J'espere qu'il vous a permis de mieux comprendre l'importance et l'utilisation du design pattern Factory. Si ce tutoriel vous a ete utile, n'hesitez pas a le partager avec vos collegues ou sur vos reseaux sociaux pour en faire profiter d'autres developpeurs. Vos commentaires et suggestions sont toujours les bienvenus : ils m'aident a ameliorer mes contenus et a mieux repondre a vos attentes.

Merci pour votre lecture et a bientot pour d'autres explorations enrichissantes dans le monde du developpement logiciel!

Track your progress

Sign in to resume reading later.

Sign in

Similar content

Comments (0)

Sign in to comment on this tutorial.

Sign in
No comments yet.