Académique Documents
Professionnel Documents
Culture Documents
Alexandre Brabant*
2024
les "Objects Calisthenics", qui sont de petits exercices et règles pour améliorer la qualité de
votre code. Vous pouvez regarder cette vidéo en français.
les design patterns au complet, sur un site appelé refactoring.guru en anglais, certes, mais
en accès libre et gratuit ;
des ouvrages payants, cette fois, mais qui sont des bibles pour le développement logiciel :
Clean Code (dès maintenant !) et Clean Architecture (si vous avez déjà un peu d'expé-
rience).
Enn, on ne peut pas ignorer le livre fondateur du "gang of four" : Design Patterns : Elements
of Reusable Object-Oriented Software.
En développement logiciel, la majorité des fonctionnalités que l'on vous demandera de coder ré-
pondent à des problèmes très communs et forcément déjà résolus.
Dans ce cas, vous pouvez être tenté de réutiliser votre code, ou alors le code d'une librairie open
source partagée et maintenue par la communauté.
En vous professionnalisant, vous utiliserez souvent des frameworks logiciels qui fournissent un en-
semble d'outils répondant à des problèmes communs : Symfony pour le langage PHP, ou encore
Django pour le langage Python.
Les frameworks sont très puissants, mais ils nécessitent en contrepartie un temps d'apprentissage
assez long. D'autre part, si vous intégrez une équipe qui n'utilise pas le même langage ou le même
framework que le vôtre, vous aurez quelques dicultés d'adaptation.
Les design patterns sont des solutions typiques à des problèmes communs en développement logi-
ciel : ils ne sont pas une implémentation concrète d'une solution à un problème, mais plutôt une
* Adaptation d'un cours de Mickaël Andrieu (mis à jour le 16/02/2024)
stratégie à appliquer pour le résoudre de façon élégante et maintenable.
Ils sont souvent confondus avec les algorithmes, qui eux aussi fournissent une solution à des pro-
blèmes communs. Mais là où l'algorithme est à appliquer exactement sur le modèle d'une recette
de cuisine, les design patterns sont à adapter à votre code : un design pattern peut être implémenté
de multiples façons.
En développement logiciel, un anti-pattern est une erreur courante de conception. Les Anglais
parlent parfois de "code smell" (en français, "du code qui pue" !).
Imaginez que l'entreprise pour laquelle vous travaillez assure essentiellement du transport de mar-
chandises par la route.
Dans votre application, vous aurez probablement développé la logique business du transport di-
rectement dans la classe Truck ou Car.
Le transport par bateau va obéir à d'autres contraintes (taxes, coût, etc.) que le transport par la
route. On peut s'en sortir en ajoutant quelques conditions dans le code, mais que se passera-t-il le
jour où l'entreprise voudra également assurer du transport par avion ou par drone ?
Page 2
1. Le type de transport (le Product) dépend d'une interface.
2. Chaque type de transport est donc une implémentation concrète et diérente de l'interface.
3. La Factory dépend elle aussi d'une interface qui dénit la méthode en charge de la création
du produit. Souvent, les développeurs l'appellent factory ou create.
Bien que l'on nomme cette classe Factory, la création de produits n'est généralement pas la
responsabilité principale de cette classe, qui contient d'autres fonctions plus utiles au com-
portement attendu de ces objets.
Mettons en pratique le design pattern en mettant en place l'interface pour dénir les diérents
types de transport :
<?php
interface Transport
{
public function deliverOrder();
}
<?php
Page 3
// et toutes les autres méthodes utiles à cet objet!
}
<?php
interface TransportFactory
{
public function createTransport() : Transport;
/**
* cette fonction ne doit pas être surchargée
*/
final public function deliver()
{
return $this->createTransport()->deliverOrder();
}
}
Nous aurons donc une Factory par type de transport, qui retournera le mode de transport :
Page 4
<?php
La construction d'un objet peut prendre énormément de temps et de ressources, par exemple si elle
fait appel à des chiers, à des appels réseau ou encore à des informations que l'on retrouve en base
de données. Par souci d'optimisation de performance, on peut préférer copier un objet existant et
le modier plutôt qu'en recréer un en partant de zéro.
Pour cela, nous allons déléguer la création du clone d'un objet... à l'objet lui-même.
Page 5
1. Tout d'abord, une interface nommée Prototype contient l'unique contrat sur la fonction de
copie : ici la fonction clone().
2. Chaque objet implémentant cette interface sera donc copiable.
3. Enn, la responsabilité d'exécuter l'opération de la copie est déléguée à un Client.
De cette façon, même si l'objet est capable de "se" cloner, nous avons respecté le principe de
séparation des responsabilités (SRP).
L'opération de copie est plus rapide que l'opération d'instanciation pour les "gros" objets.
Nous créons un objet sans passer par une instanciation, il n'y aura donc pas d'opérateur new uti-
lisé : c'est un bon indice pour identier ce design pattern.
Par exemple, imaginons que nous souhaitions créer une boutique en ligne complète, et seulement
en changer le thème graphique.
Cela dit, l'opérateur clone a une limitation : toutes les propriétés de l'objet qui sont également
des objets ne seront pas clonées, mais seulement assignées en tant que référence. Il faudra donc
"compléter" l'opération de copie dans la fonction __clone().
À l'aide du design pattern Prototype, nous pouvons limiter les risques d'erreur lors de la copie,
tout en faisant directement l'opération de changement de thème.
<?php
Page 6
class Shop
{
private $theme;
use Shop;
use Theme;
interface ShopClonable
{
public function cloneWithTheme(Shop $shop, Theme $theme) : Shop;
}
Et maintenant, un cas d'utilisation dans une classe dont ce serait la responsabilité (un Client) :
<?php
return $newShop;
}
}
Page 7
Et voici une mise en pratique :
<?php
Jusque-là, nous avons parlé des design patterns comme de solutions à des problèmes communs de
conception logicielle.
Pourtant, le design pattern Singleton est souvent décrié et reconnu comme étant plutôt un "anti-
pattern" (que vous pourriez aussi appeler une "fausse bonne idée").
Le design pattern Singleton est un design pattern de création qui applique une contrainte sur une
classe : il ne pourra y avoir qu'une et une seule instance possible de cette classe tout
en fournissant un accès global à cette instance de classe.
Le meilleur exemple d'utilisation d'un Singleton en PHP, c'est lorsque l'on souhaite créer une
connexion à une base de données.
En eet, lorsque les informations d'authentication à la base de données ont été fournies, quel est
l'intérêt de repasser les informations d'authentication et/ou de recréer la connexion à chaque fois
que nous aurons besoin de manipuler des informations ?
Page 8
2.3.1 Implémentez un Singleton
Comme nous pouvons le voir dans le schéma UML précédent, deux conditions sont requises
pour créer un Singleton :
Il faut rendre le constructeur inaccessible. En PHP, il faut que la fonction __construct
soit déclarée privée, et l'on ne pourra donc plus instancier l'objet à l'aide de l'opérateur new.
Il faut pouvoir récupérer une instance de l'objet à l'aide d'une fonction publique statique.
Cette fonction appellera le constructeur privé et conservera l'objet créé dans une propriété
privée statique. Une fois appelée, la fonction privée de construction ne sera jamais rappelée !
Reprenons l'exemple de la base de données en créant une classe Database à l'aide d'un Singleton :
<?php
use PDO;
class Database
{
private static $instance = null;
return self::$instance;
}
Page 9
}
Et un exemple d'utilisation :
<?php
PDO_DSN = 'mysql:host=localhost;dbname=test';
USER = 'root';
PASSWD = 'password';
$connection = Database::getInstance()->getConnection();
$stmt = $connection->prepare('SELECT * FROM users');
$users = $stmt->execute();
Inconvénients :
Passer par un Singleton peut cacher des problèmes de conception : pour la classe Database,
si les constantes PDO_DSN, USER et PASSWD n'ont pas été dénies "avant" l'appel à la fonction
getInstance(), l'objet sera invalide.
Il est dicile de tester un Singleton, puisqu'une fois qu'il est construit, il ne peut plus être
changé ! Compliqué alors de vérier le comportement de l'objet en fonction de diérentes
valeurs des constantes PDO_DSN, USER et PASSWD.
À moins que vous n'ayez réellement besoin d'avoir une seule instance d'un objet dans votre appli-
cation, il n'est pas conseillé d'implémenter un Singleton. Il existe une autre méthode permettant
d'accéder à un objet de façon globale. . .
Page 10