JeuWeb - Crée ton jeu par navigateur
singleton et héritage - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : singleton et héritage (/showthread.php?tid=4945)



singleton et héritage - Ter Rowan - 27-06-2010

coucou,

pour mes factory, j'ai construit une classe mère de factory qui possède 80% des méthodes de chaque classe factory spécialisé

F1 extends Fmère
F2 extends Fmère, etc...

j'aimerais que chaque factory soit unique (donc passer par un motif singleton pour chaque classe fille)

le problème c'est que si j'applique le singleton en basique, ce sera un singleton basé sur Fmère, je n'aurais donc pas un F1 et un F2


j'ai donc pensé à un multiton, indicé sur la classe

dans Fmère : static instance = array()

mais voilà comment indiquer la classe à Fmère de manière générique je n'ai pas envie d'avoir un getInstance dans chaque classe factory du type :

F1 :: getInstance(){ parent :: getInstance('F1');}
F2 :: getInstance(){ parent :: getInstance('F2');}
F3 :: getInstance(){ parent :: getInstance('F3');}

je préférerais de loin avoir uniquement un getInstance dans Fmère

mais voilà, je ne sais pas récupérer la classe ( je ne peux pas faire de get_classe($this) puisque $this n'existe pas au démarrage du motif singleton/multiton)


alors voilà, si vous pouvez m'éclairer (soit dans ma piste multiton soit dans un autre)

l'idée étant que je ne pose du code que dans la classe mère, pas dans chacune de mes classes à "singlotiser"


RE: singleton et héritage - Shudrum - 27-06-2010

Si tu modifies simplement ton getInstance en getInstance($className) ?


RE: singleton et héritage - Ter Rowan - 27-06-2010

c'est justement cela que j aimerais éviter

en effet, soit je demande cela au programmeur "client" de ma classe (en plus c 'est moi le client ^^)

et ca donne

$toto = maclasse::getInstance('maclasse');


soit dans maclasse, je renvoie son nom (ce que j'ai illustré dans mon premier post)

je trouve ça vraiment pas top, redondant, etc...

si il reste que ça oui, mais c'est d'un moche


RE: singleton et héritage - Anthor - 27-06-2010

A partir de php 5.3, tu peux utiliser le "Late Static Bindings". En gros ça te permet d'avoir le nom de la classe appelé durant l'exécution avec le mot clé static.
On remarquera que l'exemple utilise le nouvel opérateur ternaire qui permettre d'omettre la partie centrale.


abstract class Singleton
{
protected function __construct() {}

final private function __clone() {}

final static public function getInstance()
{
static $instance = null;

return $instance ?: $instance = new static;
}
}

class Test extends Singleton
{
public function test()
{
echo __CLASS__ . PHP_EOL;
}
}

$test = Test::getInstance();

Sinon tu peux utiliser get_called_class :

class Singleton
{
static $instance = array();

protected function __construct() {}

final private function __clone() {}

final static public function getInstance()
{
$class = get_called_class();

if( ! isset( self::$instances[$c] ) )
{
self::$instances[$class] = new $class;
}

return self::$instances[$class];
}
}

class Test extends Singleton
{
public function test()
{
echo __CLASS__ . PHP_EOL;
}
}

$test = Test::getInstance();

Il y a d'autres possibilités, par contre ne pas confondre le singleton et le factory.
Si t'as factory est unique ou héritée, alors elle ne sert pas à instancier d'autres classes.
La tu as uniquement un singleton, d'après tes explications. Avec plus de code on pourrait surement mieux cibler le besoin.


RE: singleton et héritage - Ter Rowan - 27-06-2010

(27-06-2010, 03:18 PM)Anthor a écrit : Sinon tu peux utiliser get_called_class :
je connaissais pas cette méthode mais c'était ce que je recherchais à l'origine Smile

(27-06-2010, 03:18 PM)Anthor a écrit : A partir de php 5.3, tu peux utiliser le "Late Static Bindings". En gros ça te permet d'avoir le nom de la classe appelé durant l'exécution avec le mot clé static.
On remarquera que l'exemple utilise le nouvel opérateur ternaire qui permettre d'omettre la partie centrale.
cette partie là est plus hard core, mais elle me plait bien, faut que je regarde si je pense pouvoir la maintenir ^^


(27-06-2010, 03:18 PM)Anthor a écrit : Il y a d'autres possibilités, par contre ne pas confondre le singleton et le factory.
Si t'as factory est unique ou héritée, alors elle ne sert pas à instancier d'autres classes.
La tu as uniquement un singleton, d'après tes explications.
pas sûr d'avoir bien compris, j en arrive à la suite

(27-06-2010, 03:18 PM)Anthor a écrit : Avec plus de code on pourrait surement mieux cibler le besoin.
le problème c'est la taille du code à analyser, je ne sais pas trop quoi publier mais voici quelques illustrations

Code PHP :
<?php 
/* méthode pour générer les objets dans la classe mère (j'ai épuré d'un certain nombre de contrôle et tests)*/
/**
* Méthode "par défaut" qui enregistre un nouvel objet si celui ci n'est pas déjà enregistré.
* le comportement pour l'objet principal (et non un de ses modules) est
* vérifie que l'objet n'est pas déjà créé => _donnees[ champ(cle) ] inexistant
* si pas créé, stock l'objet dans _donnees[ champ(cle)]
* @param res tableau résultat de la lecture sql, indicé par les champs
* @param module correspond au nom du module à charger
* @since 1.0
* @return true si chargement s'est bien passé, false sinon (que ce soit erreur ou déjà présent)
*/
protected function Enregistre($res, $module)
{
$objetRes = $this->CreerObjet($res);

if (
false === $objetRes )
return
false;

if (!isset(
$this->_donnees[ $res[ $this->_infosRequetes[$module]['cle'] ] ]) )
{
$this->_donnees[ $res[ $this->_infosRequetes[$module]['cle'] ] ] = $objetRes;
return
true;
}
else
return
false;
}

}

/* à noter la méthode CreerObjet dépend de la classe fille */

// exemple pour la "factory" personnage, du très simple
public function CreerObjet($res)
{
return new
classRootPersonnage($res);
}

// exemple pour la "factory" action, du plus compliqué
public function CreerObjet($res)
{
// si l'action est déjà partiellement chargée, on continue, sinon on crée une nouvelle action
if (isset($this->_donnees[ $res[ $this->_infosRequetes['_']['cle'] ]] ))
$action = $this->_donnees[ $res[ $this->_infosRequetes['_']['cle']] ];
else
{
if (!isset(
self::$_classes[$res['id_classe']]))
throw new
classErreur (NULL, 999, array( 'id_classe' => $res['id_classe']) );
$classe = self::$_classes[ $res['id_classe'] ];
$action = new $classe($res);
}

if (
$res['type'] !== NULL)
{
if (!isset(
self::$_modules[$res['type']]))
throw new
classErreur (NULL, 999, array( 'type' => $res['type']) );

$action->CreerModule( ClassBDDListeActions::$_modules[$res['type']] );
$action->getModule(ClassBDDListeActions::$_modules[$res['type']])->addContrainte($res);

}
return
$action;
}
remarque peut être que le terme "factory est un peu dévoyé dans ma démarche mais je pense tenir une ligne cependant

en tout cas merci !