Co to jest wzorzec projektowania fabryki w PHP?


88

To mnie wprawia w zakłopotanie, najprościej mówiąc, co to robi? Udawaj, że wyjaśniasz swojej matce lub komuś, co prawie się podoba.


115
Moja mama i tak by tego nie zrozumiała ...
Bruno Reis

6
@JasonDavis Wciąż odpowiadam na twoje pytania ... Zaczynam czuć się jak prześladowca.
Tyler Carter

Odpowiedzi:


175

Fabryka tworzy obiekt. Więc jeśli chcesz budować

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

Nie chciałbyś polegać na konieczności wykonywania następującego kodu za każdym razem, gdy tworzysz obiekt

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

W tym miejscu pojawiłaby się fabryka. Definiujemy fabrykę, która zadba o to za nas:

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

Teraz wszystko, co musimy zrobić, to

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

Prawdziwą zaletą jest to, że chcesz zmienić klasę. Powiedzmy, że chcieliśmy przejść do innej klasy C:

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

lub nową ClassB:

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

Teraz możemy użyć dziedziczenia, aby łatwo zmodyfikować sposób tworzenia klasy, aby umieścić inny zestaw klas.

Dobrym przykładem może być ta klasa użytkownika:

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

W tej klasie $datajest to klasa, której używamy do przechowywania naszych danych. Teraz dla tej klasy, powiedzmy, że używamy sesji do przechowywania naszych danych. Fabryka wyglądałaby tak:

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

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

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

Teraz powiedzmy, że zamiast tego chcemy przechowywać wszystkie nasze dane w bazie danych, naprawdę łatwo to zmienić:

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

Fabryki to wzorzec projektowy, którego używamy do kontrolowania sposobu, w jaki składamy obiekty, a użycie prawidłowych wzorców fabryki pozwala nam tworzyć niestandardowe obiekty, których potrzebujemy.


3
To było dużo pisania. Teraz będę musiał kiedyś umieścić to na mojej wiki.
Tyler Carter

1
Miły i pomocny. Czapki z głów dla ciebie kolego.
stefgosselin

1
Jaka jest różnica / korzyścią kodzie $obj = $factory->build();ponad $obj = new whateverClass();? Również w innej klasie (powiedzmy classZ), która zależy od danych klasy A, gdzie w classZ użyłbyś metody fabrycznej? Zasadniczo nadal tworzysz instancję klasy (classZ) w klasie (classA), co oznacza brak testowania. np. fabryka po prostu wydaje się być ładunkiem kodu do wykonania newza pomocą metody, a nie tylko używania new.
James,

19

Jak prawdziwa fabryka, coś tworzy i zwraca.

Wyobraź sobie coś takiego

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

lub metodą fabryczną

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

Implementacja metody fabrycznej utworzy nową instancję i zwróci ją.


1
Niezły przykład, zadziwia mnie, jak różnorodne są implementacje tego wzorca. Zakładam, że po wywołaniu statycznym można uzyskać odniesienie do instancji, aby później ponownie użyć tej samej instancji? tj. $ joe = Joe :: Factory () -> powiedz ('cześć');
stefgosselin

z pewnością tak jak w 5.6 można również zrobić (nowy Joe ()) -> powiedz ('cześć');
Pancho

12

Wzorzec projektowania fabryki jest bardzo dobry, gdy masz do czynienia z wieloma zasobami i chcesz wdrożyć abstrakcję wysokiego poziomu.

Podzielmy to na inną sekcję.

Załóżmy, że musisz zaimplementować abstrakcję, a użytkownik Twojej klasy nie musi przejmować się tym, co zaimplementowałeś w definicji klasy.

Musi się po prostu martwić o użycie metod klasowych.

np. Masz dwie bazy danych dla swojego projektu

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

}

Twoja klasa Factory zajmie się utworzeniem obiektu do połączenia z bazą danych.

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

}

Użytkownik musi tylko podać nazwę typu bazy danych

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

Wynik:

MySQL Database Connection
Your mysql select query execute here

W przyszłości możesz mieć inną bazę danych, nie musisz zmieniać całego kodu, wystarczy przekazać nowy typ bazy danych, a inny kod będzie działał bez wprowadzania żadnych zmian.

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

Wynik:

Oracle Database Connection
Your oracle select query execute here

Mam nadzieję, że to pomoże.


1

Ogólnie „fabryka” coś produkuje: w przypadku programowania obiektowego, „wzorzec projektu fabrycznego” wytwarza obiekty.

Nie ma znaczenia, czy jest w PHP, C # czy jakimkolwiek innym języku zorientowanym obiektowo.


1

Wzorzec projektu fabrycznego (wzorzec fabryczny) służy do luźnego połączenia. Podobnie jak znaczenie fabryki, dane do fabryki (wytwarzają dane) dla użytkownika końcowego. W ten sposób fabryka przerywa ścisłe powiązanie między źródłem danych a procesem danych.



0

Ta odpowiedź odnosi się do innego postu, w którym Daniel White powiedział, że używa fabryki do tworzenia połączenia MySQL przy użyciu wzorca fabrycznego.

W przypadku połączenia MySQL wolałbym raczej użyć wzorca singleton, ponieważ chcesz użyć tego samego połączenia do uzyskiwania dostępu do bazy danych, a nie tworzyć innego.


0

Klasyczne podejście do tworzenia instancji obiektu to:

$Object=new ClassName();

PHP ma możliwość dynamicznego tworzenia obiektu na podstawie nazwy zmiennej przy użyciu następującej składni:

$Object=new $classname;

gdzie zmienna $ classname zawiera nazwę klasy, którą chcesz utworzyć.

Tak więc klasyczny faktoring obiektowy wyglądałby tak:

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

a jeśli wywołasz funkcję getInstance („Product”), ta fabryka utworzy i zwróci obiekt Product. W przeciwnym razie, jeśli wywołasz funkcję getInstance („Customer”), ta fabryka utworzy i zwróci obiekt typu Customer (utworzony z klasy Customer ()).

Nie ma już takiej potrzeby, można wysłać „Produkt” lub „Klient” (dokładne nazwy istniejących klas) jako wartość zmiennej do dynamicznej instancji:

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

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

0

Dla przypomnienia, w prostych słowach, fabryka, jak powiedział @Pindatjuh, zwraca obiekt.

Więc jaka jest różnica w konstruktorze? (to robi to samo)

  1. konstruktor używa własnej instancji.
  2. Coś, co chcę, więc coś bardziej zaawansowanego i nie chcę nadużywać obiektu (ani dodawać zależności).
  3. Konstruktor jest wywoływany podczas tworzenia każdej instancji. Czasami tego nie chcesz.

    Na przykład, powiedzmy, że za każdym razem, gdy tworzę obiekt klasy Account, czytam z bazy danych plik i używam go jako szablonu.

Korzystanie z konstruktora:

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

Korzystanie z fabryki:

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;
      }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.