Was ist ein Factory Design Pattern in PHP?

88

Das verwirrt mich im einfachsten Sinne, was macht es? Stellen Sie sich vor, Sie erklären es Ihrer Mutter oder jemandem fast bitte.

JasonDavis
quelle
114
Meine Mutter würde es sowieso nicht verstehen ...
Bruno Reis
6
@ JasonDavis Ich beantworte immer wieder deine Fragen ... Ich fühle mich langsam wie ein Stalker.
Tyler Carter

Antworten:

174

Eine Fabrik erstellt ein Objekt. Also, wenn Sie bauen wollten

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

Sie möchten sich nicht darauf verlassen, dass Sie bei jedem Erstellen des Objekts den folgenden Code ausführen müssen

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

Hier würde die Fabrik ins Spiel kommen. Wir definieren eine Fabrik, die das für uns erledigt:

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

Jetzt müssen wir nur noch tun

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

Der eigentliche Vorteil ist, wenn Sie die Klasse ändern möchten. Nehmen wir an, wir wollten eine andere Klasse C bestehen:

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

oder eine neue Klasse B:

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

Jetzt können wir die Vererbung verwenden, um die Art und Weise, wie die Klasse erstellt wird, einfach zu ändern und eine andere Gruppe von Klassen einzufügen.

Ein gutes Beispiel könnte diese Benutzerklasse sein:

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

In dieser Klasse $dataist die Klasse, in der wir unsere Daten speichern. Nehmen wir für diese Klasse an, wir verwenden eine Sitzung, um unsere Daten zu speichern. Die Fabrik würde so aussehen:

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

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

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

Nehmen wir an, wir möchten stattdessen alle unsere Daten in der Datenbank speichern. Es ist wirklich einfach, sie zu ändern:

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

Fabriken sind ein Entwurfsmuster, mit dem wir steuern, wie wir Objekte zusammensetzen. Durch die Verwendung korrekter Fabrikmuster können wir die benutzerdefinierten Objekte erstellen, die wir benötigen.

Tyler Carter
quelle
3
Das war viel Tippen. Jetzt muss ich es irgendwann in mein Wiki stellen.
Tyler Carter
1
Schön und hilfsbereit. Hut ab vor dir Kumpel.
Stefgosselin
1
Was ist der Unterschied / Nutzen Ihres Codes $obj = $factory->build();gegenüber $obj = new whateverClass();? Wo würden Sie in einer anderen Klasse (z. B. classZ), die von den Daten von classA abhängt, in classZ die Factory-Methode verwenden? Sie instanziieren im Wesentlichen immer noch eine Klasse (classZ) innerhalb einer Klasse (classA), was bedeutet, dass keine Tests durchgeführt werden. zB scheint die Fabrik nur eine Menge Code zu sein, die newüber eine Methode ausgeführt werden kann, anstatt nur zu verwenden new.
James
18

Wie eine echte Fabrik schafft sie etwas und gibt es zurück.

Stellen Sie sich so etwas vor

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

oder eine Fabrikmethode

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

Durch die Implementierung der Factory-Methode wird eine neue Instanz erstellt und zurückgegeben.

Alex
quelle
1
Schönes Beispiel, erstaunt mich, wie vielfältig die Implementierungen für dieses Muster sind. Wenn ich statisch aufgerufen werde, gehe ich davon aus, dass man einen Verweis auf die Instanz erhalten kann, um dieselbe Instanz später wiederzuverwenden. dh $ joe = Joe :: Factory () -> say ('Hallo');
Stefgosselin
sicherlich wie bei 5.6 kann man auch machen (neuer Joe ()) -> sagen ('hallo');
Pancho
12

Das Factory-Design-Muster ist sehr gut, wenn Sie mit mehreren Ressourcen arbeiten und eine Abstraktion auf hoher Ebene implementieren möchten.

Lassen Sie uns dies in einen anderen Abschnitt unterteilen.

Angenommen, Sie müssen die Abstraktion implementieren und der Benutzer Ihrer Klasse muss sich nicht darum kümmern, was Sie in der Klassendefinition implementiert haben.

Er / Sie muss sich nur um die Verwendung Ihrer Klassenmethoden kümmern.

zB Sie haben zwei Datenbanken für Ihr Projekt

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

}

Ihre Factory-Klasse kümmert sich um die Erstellung eines Objekts für die Datenbankverbindung.

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

}

Der Benutzer muss nur den Namen des Datenbanktyps übergeben

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

Ausgabe:

MySQL Database Connection
Your mysql select query execute here

In Zukunft haben Sie möglicherweise eine andere Datenbank, dann müssen Sie nicht den gesamten Code ändern, sondern müssen nur den neuen Datenbanktyp übergeben. Anderer Code wird ohne Änderungen ausgeführt.

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

Ausgabe:

Oracle Database Connection
Your oracle select query execute here

Hoffe das wird helfen.

Shailesh Sonare
quelle
1

Im Allgemeinen produziert eine "Fabrik" etwas: Im Fall der objektorientierten Programmierung produziert ein "Fabrikdesignmuster" Objekte.

Es spielt keine Rolle, ob es sich um PHP, C # oder eine andere objektorientierte Sprache handelt.

Pindatjuh
quelle
1

Factory Design Pattern (Factory Pattern) dient zur losen Kopplung. Wie die Bedeutung von Fabrik, Daten zu einer Fabrik (Daten produzieren) zum Endbenutzer. Auf diese Weise unterbricht die Fabrik die enge Kopplung zwischen Datenquelle und Datenprozess.

N Zhang
quelle
0

Diese Antwort bezieht sich auf einen anderen Beitrag, in dem Daniel White Factory zum Erstellen einer MySQL-Verbindung mithilfe des Factory-Musters verwendet.

Für die MySQL-Verbindung würde ich lieber ein Singleton-Muster verwenden, da Sie dieselbe Verbindung für den Zugriff auf die Datenbank verwenden möchten, ohne eine andere zu erstellen.

Marcin - user2676388
quelle
0

Der klassische Ansatz zum Instanziieren eines Objekts lautet:

$Object=new ClassName();

PHP kann ein Objekt aus dem Variablennamen mithilfe der folgenden Syntax dynamisch erstellen:

$Object=new $classname;

Dabei enthält die Variable $ classname den Namen der Klasse, die instanziiert werden soll.

Das klassische Objekt-Factoring würde also so aussehen:

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

und wenn Sie die Funktion getInstance ('Product') aufrufen, erstellt diese Factory ein Product-Objekt und gibt es zurück. Wenn Sie andernfalls die Funktion getInstance ('Customer') aufrufen, erstellt diese Factory ein Objekt vom Typ Customer (erstellt aus der Klasse Customer ()) und gibt es zurück.

Es besteht keine Notwendigkeit mehr dafür, man kann 'Produkt' oder 'Kunde' (genaue Namen vorhandener Klassen) als Wert der Variablen für die dynamische Instanziierung senden:

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

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

In einfachen Worten, eine Fabrik wie @Pindatjuh gibt ein Objekt zurück.

Was ist der Unterschied zu einem Konstruktor? (das macht das gleiche)

  1. Ein Konstruktor verwendet seine eigene Instanz.
  2. Etwas, das ich möchte, also etwas Fortgeschritteneres und ich möchte das Objekt nicht aufblähen (oder Abhängigkeiten hinzufügen).
  3. Der Konstruktor wird aufgerufen, wenn jede Instanz erstellt wird. Manchmal willst du das nicht.

    Angenommen, ich lese jedes Mal, wenn ich ein Objekt der Klasse Account erstelle, eine Datei aus der Datenbank und verwende sie als Vorlage.

Konstruktor verwenden:

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

Werkseitig:

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