Le design pattern Singleton

Comment restreindre l'instanciation d'une classe à un seul objet ?

Le but de ce tutoriel est d'expliquer le design pattern Singleton.

Le Singleton permet de garantir qu'une classe ne peut être instanciée qu'une seule fois. Ce design pattern est l'un des plus simples à comprendre, c'est souvent d'ailleurs le premier qui est étudié dans les écoles.

Un peu de vocabulaire

  • Variable statique : C'est une variable partagée par toutes les instances d'une classe. Elles sont également appelées variables de classe.
  • Méthode statique : C'est une méthode qui manipule des informations indépendantes d'une instance de la classe. Pour appeler une méthode statique, bien que ce soit possible, nous ne devons pas utiliser une instance mais directement le nom de la classe : $objet::methodeStatique() fonctionne mais NomClasse::methodStatique() a plus de sens. Dans cette méthode le mot clé "this" ne peut pas être utilisé et seules les variables statiques et les autres méthodes statiques peuvent être appelées. Elles sont également appelées méthodes de classe.
  • Constructeur : Comme son nom l'indique, c'est la méthode qui permet de construire un objet. Le constructeur est appelé automatiquement lorsque le mot clé "new" est utilisé. Dans la plupart des langages informatiques, si aucun constructeur n'est défini explicitement dans la classe, il existe un constructeur par défaut.

Le Singleton

Comme dit précédemment, le Singleton permet de garantir l'unicité de l'instanciation d'une classe.

Prenons l'exemple d'un jeu d'échecs, nous avons plusieurs tours ou cavaliers mais nous voulons être absolument certain de ne pouvoir créer qu'un seul plateau de jeu.

Interdiction donc de faire :

A ne pas faire

$plateau = new Plateau(); $plateau = new Plateau();

Comme vous vous en doutez, il faut utiliser le design pattern Singleton sur la classe Plateau pour résoudre ce problème.

Le principe consiste à interdire l'utilisation du mot clé "new" aux développeurs en le rendant privé, c'est la classe qui l'utilisera elle-même. Nous aurons besoin d'une méthode qui, lors d'un premier appel, créera une instance et qui, ensuite, retournera toujours cette même instance. C'est dans cette méthode (appelons la getInstance) que le mot clé "new" sera utilisé.

Dans l'exemple ci-dessous nous allons utiliser un identifiant généré par la fonction PHP uniqid. Cet identifiant n'a aucun rapport avec le singleton, il est là juste pour vous montrer que ce sera toujours la même instance qui sera retournée.

Plateau.php

class Plateau { private static $instance = null; public $id; private function __construct() { $this->id = uniqid(); } public static function getInstance() { if (!isset(self::$instance)) { /* Equivalent à new Plateau() */ self::$instance = new static; } return (self::$instance); } } $plateau = Plateau::getInstance(); echo $plateau->id; // 536f64698c81b $plateau = Plateau::getInstance(); echo $plateau->id; // 536f64698c81b /* Fatal error: Call to private Plateau::__construct() from invalid context in... */ $plateau = new Plateau();

Le Singleton est un outil précieux qui va vous aider dans de nombreux cas. Néanmoins, attention à ne pas l'utiliser à outrance au risque de le regretter. Imaginez qu'au bout du compte l'objet que vous croyiez unique ne l'est pas : un échiquier en 3D contient plusieurs plateaux par exemple.

Le singleton possède d'autres lacunes sévères, par exemple :

  • Dans certains langages les Singletons ne peuvent pas avoir de classes enfants.
  • Ils ne sont pas supprimés par le garbage collector.
  • Ils peuvent provoquer facilement des effets de bord.
  • Ils ne sont pas sérializables.
  • etc...

Pour toutes ces raisons, le Singleton est de moins en moins apprécié et beaucoup le considèrent même comme un anti-pattern. Prudence donc...