Le pattern Singleton est trés souvent une bonne alternative à l'utilisation de classes possédant uniquement des méthodes statiques. Il permet de n'instancier qu'une seule fois une classe, et d'accéder toujours à cette même instance au moyen d'une méthode statique. Une brillante explication a déjà été faite par petepx dans son ticket DESIGN PATTERNS #1.
Sur le même principe, lors de la création de mon moteur de blog, je voulais économiser le plus possible de requêtes SQL, et donc éviter d'instancier deux fois le même objet. Par exemple, pour un ticket, il peut appraître trois fois sur la page d'accueil, dans des templates (et donc des scripts PHP) différents :
- Dans le menu "Dernières entrées"
- Dans le menu "Derniers commentaires"
- Dans le contenu principal
Comme tout enregistrement d'une base de données bien concue, chaque ticket possède évidemment un identifiant unique, qui va alors me servir à distinguer le ticket que je veux en transmettant cet identifiant à ma méthode statique. Cet identifiant va également servir d'indice pour une propriété de type tableau stockant toutes les instances déjà créées.
Voici comment cela se présente en PHP4, qui je vous le rappelle n'offre pas la possibilité de faire des propriétés statiques. Il faut donc contourner cette limitation par l'utilisation de variables globales :// Déclaration de la classe
Voici ce que cela donnerait en AS2 :
class Ticket {
// Identifiant du ticket
var $_id;
// Fonction constructeur
// Accés "private"
function Ticket($id = 0) {
if ($id > 0) {
$this->_id = (int)$id;
}
}
// Methode getInstance
// Retourne une référence vers l'instance
// correspondant à l'identifiant
function &getInstance($id) {
// Si l'indice n'est pas numérique, ne retourne rien
if (!is_numeric($id)) {
return;
}
// Teste l'existance de la propriété "statique"
if (!isset($GLOBALS["INSTANCES_TICKETS"])) {
$GLOBALS["INSTANCES_TICKETS"] = Array();
}
// Teste si l'instance demandée est déjà créée
// Si ce n'est pas le cas, la classe est instanciée
if (!isset($GLOBALS["INSTANCES_TICKETS"][(int)$id])) {
$GLOBALS["INSTANCES_TICKETS"][(int)$id] = new Ticket($id);
}
// Retourne l'instance
return $GLOBALS["INSTANCES_TICKETS"][(int)$id]
}
}
// Utilisation
$monTicket =& Ticket::getInstance(124);class Ticket {
// Identifiant du ticket
private var _id:Number;
// Tickets instanciés
private static var _lstInstances:Array = new Array();
// Fonction constructeur
private function Ticket($id:Number) {
if ($id != undefined) {
this._id = Number($id);
}
}
// Méthode statique getInstance
public static function getInstance($id:Number):Ticket {
if ($id == undefined) {
return;
}
// Si l'instance demandée n'existe pas, on la crée
if (_lstInstances[$id] == undefined) {
_lstInstances[$id] = new Ticket($id);
}
// On retourne l'instance
return _lstInstances[$id];
}
}
// Utilisation
var monTicket = Ticket.getInstance(124);
Suite à cela, j'accède aux propriétés de mon ticket via des getters, qui vérifient auparavant si l'instance à bien été remplie depuis la base de données (ou depuis un XML, ou depuis un requete serveur dans le cas de Flash). Ainsi, au premier accés, les propriétés de l'objet sont renseignées, et les accés suivants se font toujours sur la même instance ! ![]()