Design Patterns : Singleton et Classe Abstraite

neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 - 1 juin 2007 à 16:02
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 - 2 juin 2007 à 16:20
Salut,

N'étant pas encore au point avec les motifs de conception, je me pose une question qui a sûrement une réponse toute bête.

J'aimerais avoir une classe abstraite dont les classes dérivées sont des singletons.

J'ai comme présentiment qu'il y a une histoire de Factory method... mais...
1/ Je n'en sais rien, à vrai dire...
2/ Je ne vois pas vraiment comment faire...

Merci d'avance...

7 réponses

neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
1 juin 2007 à 17:08
Hmmmm...

<?php

abstract class Abstraite
{
private static $_instance = array();

protected function __construct()
{
echo 'Constructeur classe abstraite';
}

abstract public static function getInstance();

protected static function _getInstance($type = '')
{
if (empty(self::$_instance[$type]))
{
self::$_instance = new $type;
}
return self::$_instance;
}
}

class Concrete extends Abstraite
{
public static function getInstance()
{
return parent::_getInstance('Concrete');
}
}


$obj = Concrete::getInstance();

?>

Ca fonctionne... Je voulais éviter de coder la méthode getInstance() dans chaque classe dérivée, mais je crois que c'est pas possible...
Je me pose de ces questions des fois...
0
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
2 juin 2007 à 00:37
Hello,

tu peux définir ton usine dans la classe abstraite parente.
Tu définies aussi un tableau d'instances (statique aussi).
dans l'usine, tu vérifies que l'instance courante n'est pas dans ce tableau, auquel cas tu renvoies l'instance courante et tu la mets dans tn tableau. Sinon, tu renvoies celle de ton tableau.
0
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
2 juin 2007 à 11:26
Salut et merci de ta réponse.

"Tu définies aussi un tableau d'instances (statique aussi)."
=> Ouais, ça ok, c'est ce que j'ai déjà.

"dans l'usine, tu vérifies que l'instance courante n'est pas dans ce tableau"
=> Tu veux dire en fonction de l' "id" défini dans l'usine, propre à chaque instance du multiton ?

"auquel cas tu renvoies l'instance courante et tu la mets dans tn tableau. Sinon, tu renvoies celle de ton tableau."
=> Le problème est justement là : je peux pas instancier la classe Abstraite, forcément. Il me faut donc instancier la classe concrète... Mais comment instancier la bonne classe concrète depuis la classe abstraite ?

C'est pour ça que finalement, l'instanciation est réellement initiée depuis la classe concrète... J'ai pas trouvé mieux...


En fait, ce que je cherche plus particulièrement, est un peu plus compliqué que ça...
Je souhaite avoir une classe abstraite qui gère des fichiers. Les classes dérivées s'occupent de types de fichiers spécifiques (xml, php, ...). J'aimerais n'avoir au maximum qu'une seule instance de chaque classe concrète, et gérer les noms de fichiers "à la volée" de manière transparente.
Je sais pas si c'est très clair...
Chaque instance de classe concrète serait assignée à une propriété d'un autre objet
$obj -> Filer = fileManager::getInstance($fichier, $type);
Cette ligne devrait retournée l'instance pour ce type de fichier (pour qu'il n'y en ait pas 250)
La question qui me vient ensuite, c'est comment faire pour que la classe fileManager sache quel fichier lire/écrire quand on fait par exemple :
$obj -> Filer -> read();

Peut-être que je me complique la vie, où que je me pose des questions qui n'ont pas lieu d'être...
0
malalam Messages postés 10839 Date d'inscription lundi 24 février 2003 Statut Membre Dernière intervention 2 mars 2010 25
2 juin 2007 à 13:01
Je me suis emmélé les pinceaux, il était tard : tu dois passer par une classe (concrête) d'usinage. La méthode d'usinage doit être dans cette classe.
Mate mon dernier code, aDB, tu verras : il y a une classe abstraite, 2 classes concrêtes, et une classe d'usinage qui se charge de renvoyer la bonne instance, et chaque instance est un singleton.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
2 juin 2007 à 13:16
En fait, j'avais déjà regardé ta source ;)
J'ai bien compris comment renvoyer la bonne instance selon ce qu'on veut faire. Mais je veux un petit truc en plus, qui n'est peut-être pas vraiment réalisable, ou alors pas aussi facilement que j'aimerais... (c'est souvent comme ça de toute façon).

J'aimerais que quand j'ai besoin de lire un fichier, je fasse appel à une instance spécifique, en fonction du type de fichier, sans réinstancier la classe pour ce type. J'aimerais stocker certaines informations concernant le fichier dans un tableau (dans une propriété de la classe concrète).

Je souhaite donc que le moteur que représente chaque classe concrète puisse gérer plusieurs fichiers de manière la plus transparente possible. L'idée est de ne pas avoir 50 moteurs pour gérer 50 fichiers.

Mais alors plus ça va, et plus je me dis que c'est pas vraiment possible.
Si je dois ouvrir 50 fichiers, je pense que ça ferait beaucoup, 50 instances...

Est-ce que tu me suis, où bien est-ce que je pars un peu trop dans les nuages ? (auquel cas il faudrait que je redescende sur Terre...)

Merci en tout cas
0
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
2 juin 2007 à 16:06
Et si j'utilise deux usines qui me renvoient des singletons ?
La première instancie une classe concrète en fonction du type de fichier à gérer.
La seconde (classe concrète, singleton) renvoie une instance d'elle-même selon le fichier à gérer. C'est cette instance-là que j'utilise dans mes scripts. Elle fait ainsi l'interface entre mon code et la classe concrète, de manière transparente.
J'ai toujours peur de ne pas être clair...

Par exemple un truc dans ce genre là :

abstract class Abstraite
{
abstract public function type();

public final function __construct()
{
echo 'Constructeur de la classe Abstraite
';
}
}

class Concrete1 extends Abstraite
{
public function type()
{
echo 'Type1';
}
}

class Concrete2 extends Abstraite
{
public function type()
{
echo 'Type2';
}
}

class Interf
{
private static $_files = array();
protected $_type;
protected $_file;

public function __construct($type, $fichier)
{
$this -> ConcreteClass = Factory::Build($type);
$this -> _type = $type;
$this -> _file = $file;
}

public static function getInterface($type, $file)
{
if (!in_array($file, self::$_files))
{
self::$_files[] = $file;
}
return new Interf($type, $file);
}
}

class Factory
{
private static $_instances = array();

public static final function Build($type)
{
if (!in_array($type, self::$_instances))
{
self::$_instances[$type] = new $type();
}
return self::$_instances[$type];
}
}
0
neigedhiver Messages postés 2480 Date d'inscription jeudi 30 novembre 2006 Statut Membre Dernière intervention 14 janvier 2011 19
2 juin 2007 à 16:20
En fait, je crois que ça sert à rien, cette "interface" : elle aura besoin d'avoir les mêmes méthodes que les classes Concrete1 et Concrete2...
0