2010-07-29 25 views
0

J'essaie actuellement de trouver la meilleure façon de créer mes objets sur mon projet PHP 5.2 actuel. J'ai fondamentalement un registre qui renvoie des objets par des clés. Si le Registre n'a pas d'objet avec la clé spécifiée, il essayera d'en créer un en appelant une méthode usine fournie au registre par construction. Regardez le code suivant à calrify:Modèle de création: "Bastard Factory", une retombée de l'usine abstraite

interface IFactory 
{ 
    public function createProduct($key); 
} 

class Registry 
{ 
    private $m_elements = array(); 
    private $m_factory; 
    public function __construct(IFactory $factory) 
    { 
     $this->m_factory = $factory; 
    } 
    public function getElement($key) 
    { 
     if (!array_key_exists($key, $this->m_elements)) 
     { 
      $this->m_elements[$key] = $this->m_factory->createProduct($key); 
     } 
     return $this->m_elements[$key]; 
    } 
} 

Parce que j'ai différentes catégories d'objets que je voudrais stocker dans différents registres J'enveloppe un ojet de registre dans un singleton pour chaque catégorie, comme ceci:

class SpecialRegistry 
{ 
    private static $instance = null; 

    public static function getInstance() 
    { 
     if(self::$instance === null) 
     { 
      self::$instance = new Registry(new SpecialFactory()); 
     } 
     return self::$instance; 
    } 
} 

Ma classe spéciale est plutôt complexe et grande avec beaucoup d'attributs et d'objets de composition différents. Parce que je ne veux pas lier ma classe spéciale à un backend spécifique, j'allais avoir des Factories différentes pour chaque backend différent (par exemple base de données MySQL ou flux de fichier). Donc, je déplacerais la logique de chargement et d'initialisation vers les usines. Cela ne fonctionnera cependant que si tous les champs de la classe spéciale sont publics à l'usine. Ils ne devraient cependant pas être public pour le reste de l'application.

En C++, je pouvais utiliser des amis pour contourner ce problème. Également ici sur le débordement de pile j'ai lu sur presque le même sujet, mais appliqué à C#. Il a dit que je devrais simplement définir tous les champs publics dans la classe spéciale et que l'usine ne retourne qu'une interface qui expose les méthodes et les attributs que je veux rendre publics à l'application. Mais puisque PHP ne supporte pas l'indication de type return, je ne suis pas capable de retourner uniquement une interface implémentée par la classe Special. Une autre façon que j'ai imaginée serait de faire en sorte que SpecialFactory hérite de la classe Special permettant d'accéder aux champs privés et protégés de l'usine. C'est ce que j'ai appelé "Bastard Factory" puisque l'usine hérite de son propre produit.

Je voudrais savoir si quelqu'un d'entre vous peut trouver un meilleur moyen de réaliser ce que je veux. Ou suis-je complètement hors piste et céder le processus d'initialisation à l'usine est un absolu non-go? Je suis curieux de vos opinions!

Répondre

1

Venant d'un arrière-plan Java, qu'en est-il de l'ajout d'un générateur? Ce constructeur pourrait exposer son état via des champs publics sur lesquels l'usine peut construire. Une fois que le constructeur est terminé, passez-le à votre classe spéciale et laissez-le charger son état à partir du constructeur.

Quelque chose comme ça dans votre usine (pseudo-code):

public function createProduct() { 
    SpecialBuilder builder = new SpecialBuilder(); 
    // Do whatever you would have done to the Special class to the builder 
    // ... 
    Special special = new Special(builder); 
    return special; 
} 

De cette façon, votre objet spécial peut encore cacher son état interne. Le seul inconvénient réel que je vois est que c'est un léger cas de surcharge d'objet.

+0

J'ai suivi votre suggestion, mais en l'adaptant un peu à PHP qui permet des tableaux associatifs multidimensionnels - qui remplacent plutôt bien SpecialBuilder. Je vous remercie! –