Qu'est-ce qu'un modèle de conception d'usine en PHP?

88

Cela me trouble, dans les termes les plus simples que fait-il? Imaginez que vous expliquez à votre mère ou à quelqu'un presque s'il vous plaît.

JasonDavis
la source
115
Ma mère ne comprendrait pas de toute façon ...
Bruno Reis
6
@JasonDavis Je continue de répondre à vos questions ... Je commence à me sentir comme un harceleur.
Tyler Carter

Réponses:

175

Une fabrique crée un objet. Donc, si vous vouliez construire

 class A{
    public $classb;
    public $classc;
    public function __construct($classb, $classc)
    {
         $this->classb = $classb;
         $this->classc = $classc;
    }
  }

Vous ne voudriez pas compter sur le fait d'avoir à faire le code suivant à chaque fois que vous créez l'objet

$obj = new ClassA(new ClassB, new Class C);

C'est là qu'interviendrait l'usine. Nous définissons une usine pour s'en occuper pour nous:

class Factory{
    public function build()
    {
        $classc = $this->buildC();
        $classb = $this->buildB();
        return $this->buildA($classb, $classc);

    }

    public function buildA($classb, $classc)
    {
        return new ClassA($classb, $classc);
    }

    public function buildB()
    {
        return new ClassB;
    }

    public function buildC()
    {
        return new ClassC;
    }
}

Maintenant, tout ce que nous avons à faire est

$factory = new Factory;
$obj     = $factory->build();

Le véritable avantage est lorsque vous souhaitez changer de classe. Disons que nous voulions passer dans un autre ClassC:

class Factory_New extends Factory{
    public function buildC(){
        return new ClassD;
    }
}

ou un nouveau ClassB:

class Factory_New2 extends Factory{
    public function buildB(){
        return new ClassE;
    }
}

Maintenant, nous pouvons utiliser l'héritage pour modifier facilement la façon dont la classe est créée, pour mettre dans un ensemble différent de classes.

Un bon exemple pourrait être cette classe d'utilisateurs:

class User{
    public $data;
    public function __construct($data)
    {
        $this->data = $data;
    }
}

Dans cette classe se $datatrouve la classe que nous utilisons pour stocker nos données. Maintenant, pour cette classe, disons que nous utilisons une session pour stocker nos données. L'usine ressemblerait à ceci:

class Factory{
    public function build()
    {
        $data = $this->buildData();
        return $this->buildUser($data);
    }

    public function buildData()
    {
        return SessionObject();
    }

    public function buildUser($data)
    {
        return User($data);
    }
}

Maintenant, disons à la place que nous voulons stocker toutes nos données dans la base de données, il est vraiment simple de les modifier:

class Factory_New extends Factory{
    public function buildData()
    {
        return DatabaseObject();
    }
}

Les usines sont un modèle de conception que nous utilisons pour contrôler la façon dont nous assemblons les objets, et l'utilisation de modèles d'usine corrects nous permet de créer les objets personnalisés dont nous avons besoin.

Tyler Carter
la source
3
C'était beaucoup de frappe. Maintenant, je vais devoir le mettre sur mon wiki à un moment donné.
Tyler Carter
1
Agréable et serviable. Chapeau à toi mon pote.
stefgosselin
1
Quelle est la différence / bénéfice de votre code $obj = $factory->build();sur $obj = new whateverClass();? De plus, dans une autre classe (disons classZ) qui dépend des données de classA, où dans classZ utiliseriez-vous la méthode factory? Vous instanciez essentiellement une classe (classZ) dans une classe (classA), ce qui signifie qu'il n'y a pas de test. par exemple, l'usine semble être une charge de code à faire newvia une méthode au lieu de simplement utiliser new.
James le
19

Comme une vraie usine, il crée quelque chose et le renvoie.

Imaginez quelque chose comme ça

$joe = new Joe();
$joe->say('hello');

ou une méthode d'usine

Joe::Factory()->say('hello');

L'implémentation de la méthode de fabrique créera une nouvelle instance et la retournera.

Alex
la source
1
Bel exemple, m'étonne à quel point les implémentations sont variées pour ce modèle. Lorsqu'il est appelé statiquement, je suppose que l'on peut obtenir une référence à l'instance pour réutiliser la même instance plus tard? ie $ joe = Joe :: Factory () -> say ('bonjour');
stefgosselin
certainement comme à 5.6 on peut aussi faire (new Joe ()) -> say ('hello');
Pancho
12

Le modèle de conception d'usine est très bon lorsque vous avez affaire à plusieurs ressources et que vous souhaitez implémenter une abstraction de haut niveau.

Décomposons cela en différentes sections.

Supposons que vous deviez implémenter l'abstraction et que l'utilisateur de votre classe n'ait pas besoin de se soucier de ce que vous avez implémenté dans la définition de classe.

Il / Elle a juste besoin de s'inquiéter de l'utilisation de vos méthodes de classe.

Par exemple, vous avez deux bases de données pour votre projet

class MySQLConn {

        public function __construct() {
                echo "MySQL Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your mysql select query execute here" . PHP_EOL;
        }

}

class OracleConn {

        public function __construct() {
                echo "Oracle Database Connection" . PHP_EOL;
        }

        public function select() {
                echo "Your oracle select query execute here" . PHP_EOL;
        }

}

Votre classe Factory se chargerait de la création de l'objet pour la connexion à la base de données.

class DBFactory {

        public static function getConn($dbtype) {

                switch($dbtype) {
                        case "MySQL":
                                $dbobj = new MySQLConn();
                                break;
                        case "Oracle":
                                $dbobj = new OracleConn();
                                break;
                        default:
                                $dbobj = new MySQLConn();
                                break;
                }

                return $dbobj;
        }

}

L'utilisateur a juste besoin de transmettre le nom du type de base de données

$dbconn1 = DBFactory::getConn("MySQL");
$dbconn1->select();

Production:

MySQL Database Connection
Your mysql select query execute here

À l'avenir, vous pouvez avoir une base de données différente, vous n'avez pas besoin de modifier tout le code, il vous suffit de passer le nouveau type de base de données et l'autre code fonctionnera sans apporter de modifications.

$dbconn2 = DBFactory::getConn("Oracle");
$dbconn2->select();

Production:

Oracle Database Connection
Your oracle select query execute here

J'espère que cela aidera.

Shailesh Sonare
la source
1

En général, une «usine» produit quelque chose: dans le cas de la programmation orientée objet, un «modèle de conception d'usine» produit des objets.

Peu importe que ce soit en PHP, C # ou tout autre langage orienté objet.

Pindatjuh
la source
1

Le modèle de conception d'usine (modèle d'usine) est pour un couplage lâche. Comme la signification de l'usine, les données à une usine (produisent des données) à l'utilisateur final. De cette manière, l'usine rompt le couplage étroit entre source de données et processus de données.

N Zhang
la source
0

Cette réponse est en relation avec un autre article dans lequel Daniel White a déclaré utiliser l'usine pour créer une connexion MySQL en utilisant un modèle d'usine.

Pour la connexion MySQL, je préfère utiliser un modèle singleton car vous souhaitez utiliser la même connexion pour accéder à la base de données et non en créer une autre.

Marcin - user2676388
la source
0

L'approche classique pour instancier un objet est:

$Object=new ClassName();

PHP a la capacité de créer dynamiquement un objet à partir du nom de la variable en utilisant la syntaxe suivante:

$Object=new $classname;

où la variable $ classname contient le nom de la classe que l'on veut instancier.

La factorisation d'objets classique ressemblerait donc à:

function getInstance($classname)
{
  if($classname==='Customer')
  {
    $Object=new Customer();
  }
  elseif($classname==='Product')
  {
    $Object=new Product();
  }
  return $Object;
}

et si vous appelez la fonction getInstance ('Product'), cette fabrique créera et retournera l'objet Product. Sinon, si vous appelez la fonction getInstance ('Customer'), cette fabrique créera et retournera un objet de type Customer (créé à partir de la classe Customer ()).

Il n'y a plus besoin de cela, on peut envoyer 'Product' ou 'Customer' (noms exacts des classes existantes) comme valeur de variable pour l'instanciation dynamique:

$classname='Product';
$Object1=new $classname; //this will instantiate new Product()

$classname='Customer';
$Object2=new $classname; //this will instantiate new Customer()
sbrbot
la source
0

Pour mémoire, en termes simples, une usine comme le dit @Pindatjuh, renvoie un objet.

Alors, quelle est la différence avec un constructeur? (ça fait la même chose)

  1. un constructeur utilise sa propre instance.
  2. Quelque chose que je veux donc quelque chose de plus avancé et je ne veux pas gonfler l'objet (ou ajouter des dépendances).
  3. Le constructeur est appelé lorsque chaque instance est créée. Parfois tu ne veux pas de ça.

    Par exemple, disons que chaque fois que je crée un objet de la classe Account, je lis un fichier dans la base de données et l'utilise comme modèle.

Utilisation du constructeur:

class Account {
      var $user;
      var $pwd;
      var ...
      public __construct() {
         // here i read from the file
         // and many other stuff
      }
}

En utilisant l'usine:

class Account {
      var $user;
      var $pwd;
      var ...
}
class AccountFactory {
      public static Create() {
         $obj=new Account();
         // here we read the file and more stuff.
         return $obj;
      }
magallanes
la source