2010-01-26 3 views
8

Les patterns Singleton et Registry étaient très simples et faciles à comprendre tout de suite, mais le pattern Factory a été quelque chose que je n'ai pas encore réussi à faire interpréter à 100%. Je pense que je pourrais le comprendre maintenant, j'ai écrit un exemple de code ci-dessous, s'il vous plaît examiner et dites-moi si c'est l'utilisation appropriée du modèle d'usine. L'échantillon est en PHP ...Est-ce ainsi que fonctionne le motif d'usine?

<?php 
/** 
* Factory.class.php 
*/ 
class Factory { 
    public static $_database; 
    public static $_cache; 
    public static $_session; 

    // Build our User object with all it's dependencies 
    public static function makeUserObject() 
    { 
     $user = new User(); 
     $user->setDatabaseObject(self::$_database); 
     $user->setCacheObject(self::$_cache); 
     $user->setSessionObject(self::$_session); 
     return $user; 
    } 

    // other objects will be here someday...... 
} 

/** 
* User.class.php 
*/ 
class User 
{ 
    public function __construct() { } 

    // inject Database Object 
    public function setDatabaseObject($databaseConnectionObject) 
    { 
     $this->_databaseObject = $databaseConnectionObject; 
    } 

    // inject Cache Object 
    public function setCacheObject($cacheObject) 
    { 
     $this->_cacheObject = $cacheObject; 
    } 

    // inject Session Object 
    public function setSessionObject($sessionObject) 
    { 
     $this->_sessionObject = $sessionObject; 
    } 

    // other methods here for User object........... 
} 

/** 
* index.php Main page that puts it all together 
* assume that classes are autoloaded into this page already 
*/ 
// Set our Database + Cache + Session objects into the Factory Object 
Factory::$_database = new Databse(); 
Factory::$_cache = new Cache(); 
Factory::$_session = new Session(); 

// Create our User object 
// The factory class will build the User object and inject all 
// it's dependencies for us =) 
$user = Factory::makeUserObject(); 

?> 

Alors basiquement la base de données, le cache et les objets de session sont créés (non représenté ici), puis ils sont ajoutés à l'objet usine, je le peut construire une méthode dans la classe d'usine pour chaque objet qui aura besoin de l'une de ces 3 dépendances et je peux définir lesquelles ils obtiennent aussi. Cela permet également de rendre les classes individuelles un peu plus portables, car je peux y injecter directement des dépendances si je le voulais sans l'objet d'usine. Est-ce que ça sonne bien? Si cela est vrai, cela semble vraiment utile


MISE À JOUR # 1

C'est basé sur ce ici un billet de blog que je lis ici http://www.potstuck.com/2009/01/08/php-dependency-injection/ ils parlent comme une « usine », j'été en utilisant un registre et beaucoup de gens me disent de regarder dans une "usine" et tout ce que j'ai lu à ce sujet n'a pas cliqué dans ma tête jusqu'à ce que je lise cet artcle mais ressemble à ce n'est pas une "usine"?


MISE À JOUR # 2
De wikipedia http://en.wikipedia.org/wiki/Factory_object En programmation orientée objet, un objet usine est un objet pour créer d'autres objets. C'est une abstraction d'un constructeur, et peut être utilisé pour implémenter divers schémas d'allocation, tels que le modèle singleton. Un objet fabrique a généralement une méthode pour chaque type d'objet qu'il est capable de créer. Ces méthodes acceptent éventuellement des paramètres définissant comment l'objet est créé, puis retournent l'objet créé. Les objets d'usine sont utilisés dans des situations où l'obtention d'un objet d'un type particulier est un processus plus complexe que la simple création d'un nouvel objet. L'objet factory peut décider de créer dynamiquement la classe de l'objet (le cas échéant), le renvoyer depuis un pool d'objets, effectuer une configuration complexe sur l'objet ou d'autres choses.

Alors peut-être cela est un « objet usine » d'une manière ... Après tout

+0

Pouvez-vous fournir une source qui décrit modèle cette 'usine'? Je connais des modèles appelés «Abstract Factory» et «Factory Method», mais pas seulement «Factory». –

+0

@Gordon wow c'est beaucoup de modèles! Donc, je suppose que ce n'est pas vraiment une usine, et je pensais que je devais enfin quelque chose de bon ici – JasonDavis

+0

@Gordon: Oui, ce sont les modèles créatifs du livre GoF :) Pas de modèle 'Factory' là-bas ... –

Répondre

6

et tendis Sommaire des commentaires ci-dessous de la question ici

Comme d'autres ont dit, ce n'est pas une usine , simplement parce qu'un modèle avec ce nom n'existe pas. C'est soit un AbstractFactory ou un FactoryMethod, bien que, de manière pragmatique, les gens se réfèrent souvent à l'un ou l'autre en disant simplement Factory et ça me va.

La session, le cache et la base de données sont généralement quelque chose que vous allez initialiser au début de votre flux d'applications, il s'agit donc essentiellement d'un travail d'amorçage. J'ai l'impression que ce que vous cherchez n'est pas tellement la création d'objets, mais leur de manutention dans toute l'application. C'est une préoccupation quelque peu différente de ce que fait un FactoryWhatever.

Comme je l'ai dit dans les commentaires, juste parce que ce n'est pas exactement un FactoryWhatever, ne signifie pas que votre code est mauvais. Si ça résout ton problème, c'est cool. Mais je pense toujours, ce que vous essayez de faire, par exemple. création et la gestion des ressources à l'exécution est mieux utilisé avec un DIServiceContainer.

Si vous ne souhaitez pas utiliser un DI conteneur maintenant pour cela, vous pouvez jeter un oeil à Zend_Application and how they bootstrap resources. C'est une alternative et laisse la possibilité à add DI containers later.

En fait, beaucoup de sujets dans vos questions précédentes ont déjà été résolus dans Zend Framework, par ex. Classes de configuration Je ne dis pas utiliser ZF, mais vous pouvez le vérifier pour voir comment ils font les choses. Bien sûr, vous pouvez regarder le otherframeworks aussi.

Certains sites de motif avec des exemples PHP:

+0

Merci pour les liens que je lisais juste cette page http://en.wikipedia.org/wiki/Factory_object et cela ressemble un peu à ce que je vais dans le code ci-dessus, je vais deff lire les liens que vous avez fournis cependant, mon projet est fondamentalement en attente jusqu'à ce que je trouve la meilleure approche à tout cela, je veux le faire bien la première fois ou du mieux que je peux de toute façon – JasonDavis

+0

Je crois, vous ne pouvez pas * le faire correctement dès le début. Penser à l'avance est bien (et nécessaire), mais il en va de même de ce qui fonctionne maintenant jusqu'à ce que ça ne marche plus, puis refactorise. – Gordon

1

ressemble plus comme le modèle Builder pour moi. Quel modèle d'usine avez-vous réellement voulu dire, AbtractFactory ou FactoryMethod? Cependant, ils traitent tous deux de l'héritage et votre code assemble simplement un objet "complexe".

+0

Ceci est basé sur ce ici http: // www .potstuck.com/2009/01/08/php-dependency-injection/Je ne suis pas vraiment sûr, j'utilise un registre et beaucoup de gens me disent de regarder dans une "usine" et tout ce que j'ai lu à ce sujet juste n'a pas cliqué dans ma tête jusqu'à ce que je lise cet artcle – JasonDavis

+0

L'article discuté est sur l'injection de dépendance pas sur les usines. Je admin que le terme Factory est parfois utilisé à des fins différentes. Mais ce n'est certainement pas l'un des modèles d'usine dans le livre du GoF. – bertolami

3

does't ressembler à une usine pour moi - pourrait être un constructeur à l'envers; 0)

Factory est un moyen de mise en œuvre et cacher instanciation?. Et il y a généralement un ensemble étant fait, mais en quelques mots ....

public interface IUser 
    { 
     void DoSomething(); 
    } 

    public class DumbUser : IUser 
    { 

     public void DoSomething() 
     { 
      // duh... what should i do? 
     } 

    } 

    public class SmartUser : IUser 
    { 

     public void DoSomething() 
     { 
      // calclulating prime numbers while baking bread 
     } 

    } 


    public class UserFactory 
    { 
     public static IUser CreateUser() 
     { 
      Random r = new Random(Environment.TickCount); 

      return r.Next(10) > 5 ? (IUser) new SmartUser() : new DumbUser(); 
     } 
    } 

    public class YourProgram 
    { 
     public void Run() 
     { 
      IUser user = UserFactory.CreateUser(); 
      user.DoSomething(); 
     } 
    } 
+0

+1 Effrontément déchiré et collé dans mes notes de modèle de conception. Première implémentation php sensible de ce modèle. Merci bud. – stefgosselin

2

Comme il semble que vous voulez simplement créer un utilisateur, je ne vois pas la nécessité d'un facteur abstrait, désormais appelée simplement à comme usine. L'idée des usines est de créer des objets qui implémentent une certaine interface. Vous voudriez être capable d'instancier deux implémentations différentes de la même interface. Le fait est que vous devrez peut-être créer ces objets encore et encore, et le changer de ObjectA à ObjectB partout dans le code est lourd. Échanger l'usine est facile, parce que c'est souvent un singleton.L'idée de la méthode usine est liée aux frameworks: Vous voulez créer une utilisation dans un code framework, mais l'implémentation réelle de l'utilisateur est dans des classes dérivées, c'est-à-dire que des utilisateurs de votre framework écrivent leur propre application. besoin de dire à l'utilisateur de votre framework "créer un objet utilisateur maintenant", qui est un appel à la méthode d'usine. L'utilisateur doit implémenter ceci. Il est également appelé Virtual Contstructor selon le GoF. Le générateur est typiquement utilisé quand il y a différentes représentations de l'objet, ce qui n'est pas vraiment le cas ici. À mes yeux, le cache, la base de données et la session pourraient être implémentés comme singletons, facilitant ainsi les complexités impliquées. Sinon, je suggère d'utiliser un ServiceLocator qui vous permet de GetDatabase, GetSession, etc. Ensuite, vous devrez passer le localisateur à l'objet utilisateur (et à bien d'autres objets) lors de la création. L'avantage est que ce localisateur peut être réutilisé dans différentes classes.

+0

Ce localisateur dont vous parlez ressemble plus à ce que je cherche. Je suis actuellement en train de stocker une référence à des objets comme la session, la base de données, le cache dans un registre, puis d'injecter le registre dans d'autres objets lors de la création, est-ce similaire? – JasonDavis

+0

Je pense que oui, essentiellement. Je vous suggère de lire ces deux articles par Martin Fowler: http://martinfowler.com/articles/injection.html http://martinfowler.com/eaaCatalog/registry.il l'explique en détail et mieux que je pourrais, aussi je suppose que 500 chars ne feront pas le travail :) En outre, vous voudrez peut-être obtenir une copie de son livre "Patterns of Enterprise Application Architecture", il vaut chaque penny. En général, je dirais que l'inversion de contrôle et l'injection de dépendances sont plus complexes que les modèles de base, dont l'un est le modèle d'usine, donc cela prend beaucoup plus loin que votre QO. – mnemosyn

5

C'est le modèle d'usine bien, mais vous pourriez avoir besoin d'une meilleure convention de nommage que de simplement l'appeler Factory. En outre, il contient des traces d'injection de dépendance.

Bien que vous puissiez l'appeler techniquement comme le motif d'usine, ce n'est probablement pas un bon usage du motif. Factory est un modèle de création qui encapsule votre code en référençant directement les noms de classes et la création d'objets comme dans les paramètres constructeurs exacts, etc. Pour obtenir les meilleurs résultats, gardez cela à l'esprit lors de la conception de vos classes et usines.

Par exemple, StackOverflow donne aux utilisateurs différents droits en fonction de leur réputation. Hypothétiquement, il pourrait avoir les types d'utilisateurs suivants:

NewbieUser  [1-100] 
BeginnerUser [101-1000] 
AverageJoeUser [1001-5000] 
VeteranUser  [5001-20000] 
PowerUser  [20001-50000] 
GodModeUser  [50001-100000] 

et un utilisateur peut être créé en regardant leur représentant. et instanciation de l'objet utilisateur correspondant en référençant directement la classe. Jon Skeet n'apparaît dans aucune catégorie au cas où vous vous poseriez la question. Voici une mise en œuvre merdique avec instanciation directe:

if(reputation >= 1001 and reputation <= 5000) { 
    AverageJoeUser user = new AverageJoeUser(); 
} 

Si plus tard sur la route que nous devions changer les noms de classe ou les utilisateurs de façon instanciés, chacun de ces cas où l'objet a été créé devrait être trouvé et changé. Beaucoup de travail si vous me demandez. Au lieu de cela, si nous avions utilisé le modèle Factory ici, le changement irait dans une seule méthode à l'intérieur de la classe Factory.

class UserFactory { 
    public static User createUser(Integer reputation) { 
     ... 
    } 
} 
+0

Je dois dire que j'aime les "noms de classement hypothétiques", je vais devoir les enregistrer pour les classements sur un futur forum que je prévois! – JasonDavis

+0

Cela signifie-t-il que Jon Skeet est au-dessus de Dieu? –

+0

@jason, cela pourrait être un excellent moyen d'éloigner les utilisateurs actifs de votre site :) – Anurag