AHRIMAN.FR

SCIENCE - NEO-EVHEMERISME - DONJONSDRAGONS

Design pattern : Singleton

Ecris par :
Mis en ligne le :
Lu :
85 fois
Twitter Facebook Google Plus Linkedin email

En génie logiciel, le singleton est un patron de conception (design pattern) dont l'objet est de restreindre l'instanciation d'une classe à un seul objet (ou bien à quelques objets seulement). Il est utilisé lorsque l'on a besoin d'exactement un objet pour coordonner des opérations dans un système. Le modèle est parfois utilisé pour son efficacité, lorsque le système est plus rapide ou occupe moins de mémoire avec peu d'objets qu'avec beaucoup d'objets similaires.

PRINCIPE

On implémente le singleton en écrivant une classe contenant une méthode qui crée une instance uniquement s'il n'en existe pas encore. Sinon elle renvoie une référence vers l'objet qui existe déjà. Dans beaucoup de langages de type objet, il faudra veiller à ce que le constructeur de la classe soit privé, afin de s'assurer que la classe ne puisse être instanciée autrement que par la méthode de création contrôlée.

Le singleton doit être implémenté avec précaution dans les applications multi-thread. Si deux threads exécutent en même temps la méthode de création alors que l'objet unique n'existe pas encore, il faut absolument s'assurer qu'un seul créera l'objet, et que l'autre obtiendra une référence vers ce nouvel objet.

La solution classique à ce problème consiste à utiliser l'exclusion mutuelle pour indiquer que l'objet est en cours d'instanciation.

IMPLEMENTATIONS

PHP 5

Voici une solution écrite en PHP :


class Singleton {
private static $_instance;

/**
* Empêche la création externe d'instances.
*/

private function __construct () {}
/**
* Empêche la copie externe de l'instance.
*/

private function __clone () {}
/**
* Renvoi de l'instance et initialisation si nécessaire.
*/

public static function getInstance () {
if (!(self::$_instance instanceof self))
self::$_instance = new self();
return self::$_instance;
}
/**
* Méthodes dites métier
*/

public function uneAction () {}
}
// Utilisation
Singleton::getInstance()->uneAction();

Il faut noter qu'avant PHP 5.3, il n'est pas possible d'hériter une classe de type Singleton. En effet, l'accesseur self:: se réfère toujours à la classe dans laquelle il est écrit.

Depuis PHP 5.3, la classe suivante fonctionne et est héritable5 :



class Singleton
{
private static $instances = array();
final private function __construct()
{
}
final public function __clone()
{
trigger_error("Le clonage n'est pas autorisé.", E_USER_ERROR);
}
final public static function getInstance()
{
$c = get_called_class();
if(!isset(self::$instances[$c]))
{
self::$instances[$c] = new $c;
}
return self::$instances[$c];
}
}

Il est aussi possible d'utiliser static::, bien plus adapté.

C++

Voici une implémentation possible en C++, connue sous le nom de "singleton de Meyers". Le singleton est un objet static et local. Attention : cette solution n'est pas sûre dans un contexte multi-thread jusqu'en C++11 ; elle sert plutôt à donner une idée du fonctionnement d'un singleton qu'à être réellement utilisée dans un grand projet logiciel. Aucun constructeur ou destructeur ne doit être public dans les classes qui héritent du singleton.



template<typename T> class Singleton
{
public:
static T& Instance()
{
static T theSingleInstance; // suppose que T a un constructeur par défaut
return theSingleInstance;
}
};
class OnlyOne : public Singleton<OnlyOne>
{
// constructeurs/destructeur de OnlyOne accessibles au Singleton
friend class Singleton<OnlyOne>;
//...définir ici le reste de l'interface
};

Dans un langage à base de prototypes, où sont utilisés des objets mais pas des classes, un singleton désigne seulement un objet qui n'a pas de copies, et qui n'est pas utilisé comme prototype pour d'autres objets.

Une autre façon de voir les choses est de mettre un booléen en statique dans la classe, qui indique si une instance est déjà créée, et de refuser la création si c'est le cas :



class Singleton
{
public:
Singleton()
{
if (alreadyCreated)
throw logic_error("Vous ne pouvez pas créer une seconde instance de la classe Singleton.");
// Sinon, on construit la classe et on déclare l'objet créé
alreadyCreated = true;
}
~Singleton()
{
// Si on veut pouvoir recréer la classe plus tard, on déclare l'objet non-existant
alreadyCreated = false;
}
protected:
static bool alreadyCreated;
};
// Et on déclare alreadyCreated comme faux au début !
bool Singleton::alreadyCreated = false;

Cette méthode permet aussi de limiter un nombre d'instances, en remplaçant le booléen par un nombre, et le test par une comparaison.


Images

Bibliographie