Fabrique : un design pattern qui construit vos objets

Un objet pour les gouverner tous.

16 octobre 2011

Le but de ce tutoriel est d'expliquer le fonctionnement du design pattern fabrique.

Factory Method (nom anglais) est l'un des designs pattern les plus simples à appréhender. Il n'en est pas moins indispensable dans bien des situations.

Un cas concret

Dans mon entreprise je développe et maintiens une application web qui peut se connecter à différentes bases de données. Le problème c'est qu'il y a une base de données MySQL, une base Oracle et bientôt une base PostGreSQL.

Cette application n'utilisant pas d'ORM, j'ai 3 classes (MySQL, Oracle et PostGreSQL) qui me permettent de me connecter aux différentes bases.

Problèmes de la situation :

  • Dans mon code il y a des "new MySQL()", "new Oracle()", "new PostGreSQL()" => si un jour l'une des bases change, je devrai repasser sur tous les fichiers.
  • Rien n'oblige les 3 classes à avoir le même squelette. Par exemple la classe MySQL peut avoir une méthode executerRequete() et la classe Oracle une méthode execReq(). Donc le jour ou la base Oracle devient une base MySQL je devrai modifier, un peu partout dans le code, des noms de méthodes et peut être même la façon de les utiliser.

Le design pattern Factory Method

Pour le premier point, ce qu'il nous faut c'est une méthode qui prend un paramètre en entrée. Selon ce paramètre, la méthode retournera une instance de l'un ou l'autre des SGBD cités ci-dessus.

Pour le deuxième point, rien de plus simple. Il suffit que les classes de SGBD implémentent une interface. Avec ce contrat, les développeurs seront obligés de donner le même squelette à un certain nombre de méthodes. Pourquoi je vous parle de ça dans un tutoriel sur la fabrique ? La réponse tout en bas.

Nous allons créer une classe "FabriqueBase" qui servira de fabrique.

FabriqueBase.php

class FabriqueBase
{
        public static function get($baseNom)
        {
                switch ($baseNom)
                {
                        case 'zaphod':
                                return (new MySQL());
                                break;
                        case 'arthur_dent':
                                return (new PostGreSQL());
                                break;
                        case 'marvin':
                                return (new Oracle());
                                break;
                }
        }
}

$base = FabriqueBase::get('zaphod');
$base->executer($requete);
...

Comme vous le voyez, je ne dois maintenant changer le code qu'à un seul endroit.

Beaucoup de développeurs ne veulent pas créer une fabrique par type de classes. Ils préfèrent créer une classe générale (souvent un Singleton) qui fabriquera tous types d'objets.

FabriqueGenerale.php

class FabriqueGenerale
{
        public static function getBase($baseNom)
        {
                switch ($baseNom)
                {
                        case 'zaphod':
                                return (new MySQL());
                                break;
                        case 'arthur_dent':
                                return (new PostGreSQL());
                                break;
                        case 'marvin':
                                return (new Oracle());
                                break;
                }
        }

        public static function getReponse($reponseNom)
        {
                switch ($reponseNom)
                {
                        case 'vie_univers_reste':
                                return (new Nombre('42'));
                                break;
                        case '1_plus_1':
                                return (new Nombre('2'));
                                break;
                }
        }
}


$base = FabriqueGenerale::getBase('zaphod');
$base->executer($requete);

...

$nombre = FabriqueGenerale::getReponse('vie_univers_reste');

Maintenant revenons sur l'interface déclarée plus haut. Je vous avais promis de vous expliquer le rapport avec la Fabrique. La subtilité de la chose réside dans le fait que j'ai utilisé PHP pour la démonstration et que c'est un langage à très faible typage. Dans un langage comme C++, Java et tous les autres, l'interface ne suffit pas. Pour qu'un groupe d'objets puisse être retourné par une méthode de la fabrique, il faut que tous les objets de ce groupe soient du même type. Dans mon exemple il faudrait donc créer une classe abstraite SGBD. Les classes MySQL, Oracle et PostGreSQL hériteraient de SGBD. SGBD contiendrait des méthodes abstraites (executer, connecter ...) pour créer, comme l'interface l'aurait faite, un contrat avec ses classes filles.

J'insiste sur le fait que la classe abstraite remplace l'interface.

A bientôt !

Par
Créateur et administrateur.

Dans la même catégorie

Le design pattern stratégie
Le design pattern chaîne de responsabilité
Le design pattern décorateur
Le design pattern Adapter
Comment générer du code à partir d'un diagramme UML ?
Le design pattern Visiteur
Le design pattern Singleton
L'injection de dépendances
Le polymorphisme
Le design pattern Double dispatch

Commentaire(s)