Cos'è un Factory Design Pattern in PHP?


88

Questo mi confonde, nei termini più semplici cosa fa? Fai finta di spiegare a tua madre oa qualcuno quasi per favore.


115
Mia madre non lo capirebbe comunque ...
Bruno Reis

6
@JasonDavis Continuo a rispondere alle tue domande ... Comincio a sentirmi uno stalker.
Tyler Carter

Risposte:


175

Una fabbrica crea un oggetto. Quindi, se volessi costruire

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

Non vorrai fare affidamento sul dover eseguire il codice seguente ogni volta che crei l'oggetto

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

È qui che entra in gioco la fabbrica. Definiamo una fabbrica che se ne occupi per noi:

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;
    }
}

Ora tutto quello che dobbiamo fare è

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

Il vero vantaggio è quando vuoi cambiare classe. Diciamo che volevamo passare in una ClassC diversa:

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

o una nuova Classe B:

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

Ora possiamo usare l'ereditarietà per modificare facilmente il modo in cui viene creata la classe, per inserire un diverso insieme di classi.

Un buon esempio potrebbe essere questa classe utente:

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

In questa classe $dataè la classe che usiamo per memorizzare i nostri dati. Ora per questa classe, diciamo di utilizzare una sessione per memorizzare i nostri dati. La fabbrica sarebbe simile a questa:

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

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

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

Ora, diciamo invece che vogliamo memorizzare tutti i nostri dati nel database, è davvero semplice cambiarlo:

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

Le fabbriche sono un modello di progettazione che utilizziamo per controllare il modo in cui mettiamo insieme gli oggetti e l'utilizzo di modelli di fabbrica corretti ci consente di creare gli oggetti personalizzati di cui abbiamo bisogno.


3
Era un sacco di digitazione. Ora dovrò metterlo sul mio wiki ad un certo punto.
Tyler Carter

1
Bello e utile. Tanto di cappello a te amico.
stefgosselin

1
Qual è la differenza / vantaggio del tuo codice $obj = $factory->build();rispetto $obj = new whateverClass();? Inoltre, in un'altra classe (diciamo classZ) che dipende dai dati di classA, dove in classZ useresti il ​​metodo factory? In sostanza stai ancora istanziando una classe (classZ) all'interno di una classe (classA), il che significa nessun test. ad esempio, la fabbrica sembra essere solo un carico di codice da fare newtramite un metodo invece di usarlo new.
James

19

Come una vera fabbrica, crea qualcosa e lo restituisce.

Immagina qualcosa di simile

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

o un metodo di fabbrica

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

L'implementazione del metodo factory creerà una nuova istanza e la restituirà.


1
Bell'esempio, mi stupisce quanto siano varie le implementazioni per questo pattern. Quando viene chiamato staticamente, presumo che si possa ottenere un riferimento all'istanza per riutilizzare la stessa istanza in seguito? cioè $ joe = Joe :: Factory () -> say ('ciao');
stefgosselin

certamente come a 5.6 si può anche fare (new Joe ()) -> say ('hello');
Pancho

12

Il modello di progettazione di fabbrica è molto buono quando si ha a che fare con più risorse e si desidera implementare un'astrazione di alto livello.

Dividiamolo in una sezione diversa.

Supponi di dover implementare l'astrazione e l'utente della tua classe non deve preoccuparsi di ciò che hai implementato nella definizione della classe.

Deve solo preoccuparsi dell'uso dei metodi di classe.

es. hai due database per il tuo progetto

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;
        }

}

La tua classe Factory si occuperà della creazione dell'oggetto per la connessione al database.

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'utente deve solo passare il nome del tipo di database

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

Produzione:

MySQL Database Connection
Your mysql select query execute here

In futuro potresti avere un database diverso, quindi non è necessario modificare l'intero codice, è sufficiente passare il nuovo tipo di database e altro codice verrà eseguito senza apportare modifiche.

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

Produzione:

Oracle Database Connection
Your oracle select query execute here

Spero che questo ti aiuti.


1

In generale una "fabbrica" ​​produce qualcosa: nel caso della programmazione orientata agli oggetti, un "modello di progettazione di fabbrica" ​​produce oggetti.

Non importa se è in PHP, C # o qualsiasi altro linguaggio orientato agli oggetti.


1

Factory Design Pattern (Factory Pattern) è per accoppiamento libero. Come il significato di fabbrica, i dati a una fabbrica (producono dati) all'utente finale. In questo modo, la fabbrica rompe lo stretto accoppiamento tra la fonte dei dati e il processo dei dati.



0

Questa risposta è in relazione ad un altro post in cui Daniel White diceva di usare factory per creare una connessione MySQL utilizzando il pattern factory.

Per la connessione MySQL preferirei utilizzare il pattern singleton poiché si desidera utilizzare la stessa connessione per accedere al database e non crearne un altro.


0

L'approccio classico per istanziare un oggetto è:

$Object=new ClassName();

PHP ha la capacità di creare dinamicamente un oggetto dal nome della variabile utilizzando la seguente sintassi:

$Object=new $classname;

dove la variabile $ classname contiene il nome della classe che si desidera istanziare.

Quindi il factoring di oggetti classico sarebbe simile a:

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

e se chiami la funzione getInstance ('Product') questa factory creerà e restituirà l'oggetto Product. Altrimenti, se chiami la funzione getInstance ('Customer'), questa factory creerà e restituirà un oggetto di tipo Customer (creato dalla classe Customer ()).

Non ce n'è più bisogno, è possibile inviare "Prodotto" o "Cliente" (nomi esatti delle classi esistenti) come valore della variabile per l'istanza dinamica:

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

$classname='Customer';
$Object2=new $classname; //this will instantiate new Customer()

0

Per la cronaca, in parole semplici, una fabbrica come ha detto @Pindatjuh, restituisce un oggetto.

Allora, qual è la differenza con un costruttore? (che fa lo stesso)

  1. un costruttore usa la propria istanza.
  2. Qualcosa che voglio quindi qualcosa di più avanzato e non voglio gonfiare l'oggetto (o aggiungere dipendenze).
  3. Il costruttore viene chiamato quando viene creata ogni istanza. A volte non lo vuoi.

    Ad esempio, diciamo che ogni volta che creo un oggetto della classe Account, leggo dal database un file e lo utilizzo come modello.

Utilizzando il costruttore:

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

Utilizzando fabbrica:

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;
      }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.