Що таке шаблон фабричного дизайну в PHP?


88

Це мене бентежить, найпростішими словами, що це робить? Прикиньтесь, що пояснюєте матері чи комусь майже будь-ласка.


115
Моя мати все одно цього не зрозуміла б ...
Бруно Рейс

6
@JasonDavis Я продовжую відповідати на ваші запитання ... Я починаю відчувати себе сталкером.
Тайлер Картер,

Відповіді:


175

Фабрика створює об'єкт. Отже, якщо ви хотіли будувати

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

Ви не хотіли б покладатися на необхідність робити наступний код кожного разу, коли створюєте об'єкт

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

Ось де б зайшов завод. Ми визначаємо фабрику, яка б про нас подбала:

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

Тепер нам залишається лише це

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

Справжня перевага полягає в тому, коли ви хочете змінити клас. Скажімо, ми хотіли пройти інший ClassC:

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

або новий ClassB:

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

Тепер ми можемо використовувати успадкування, щоб легко змінити спосіб створення класу, щоб додати інший набір класів.

Хорошим прикладом може бути цей клас користувача:

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

У цьому класі $dataє клас, який ми використовуємо для зберігання наших даних. Тепер для цього класу, скажімо, ми використовуємо Session для зберігання наших даних. Завод буде виглядати так:

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

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

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

Тепер, скажімо, замість цього ми хочемо зберегти всі наші дані в базі даних, змінити їх дуже просто:

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

Фабрики - це шаблон дизайну, який ми використовуємо для контролю того, як ми складаємо об’єкти, а використання правильних заводських зразків дозволяє нам створювати потрібні нам персоналізовані об’єкти.


3
Це було багато набору тексту. Тепер мені колись доведеться розмістити це на своїй вікі.
Тайлер Картер,

1
Приємно та корисно. Капелюх тобі, приятель.
stefgosselin

1
У чому різниця / користь від вашого коду $obj = $factory->build();більш $obj = new whateverClass();? Крім того, в іншому класі (скажімо classZ), який залежить від даних classA, де в класіZ ви б використовували заводський метод? По суті, ви все ще створюєте екземпляр класу (classZ) у класі (classA), що означає відсутність тестування. наприклад, фабрика просто здається навантаженням коду, який потрібно зробити newза допомогою методу, а не просто використовувати new.
Джеймс

19

Як фабрика реального життя, вона щось створює і повертає.

Уявіть щось подібне

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

або фабричним способом

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

Реалізація фабричного методу створить новий екземпляр і поверне його.


1
Приємний приклад, дивує мене, наскільки різноманітні реалізації для цього шаблону. При статичному виклику я припускаю, що можна отримати посилання на екземпляр для повторного використання того самого екземпляру пізніше? тобто $ joe = Joe :: Factory () -> say ('привіт');
stefgosselin

звичайно, на 5.6 можна також зробити (new Joe ()) -> say ('hello');
Панчо

12

Заводський шаблон дизайну дуже хороший, коли ви маєте справу з кількома ресурсами і хочете застосувати абстракцію високого рівня.

Давайте розберемо це на інший розділ.

Припустимо, вам доведеться застосувати абстракцію, і користувачеві вашого класу не потрібно дбати про те, що ви реалізували у визначенні класу.

Йому / їй просто потрібно турбуватися про використання методів вашого класу.

наприклад, у вас є дві бази даних для вашого проекту

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

}

Ваш заводський клас подбав би про створення об’єкта для підключення до бази даних.

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

}

Користувачеві просто потрібно передати ім'я типу бази даних

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

Вихід:

MySQL Database Connection
Your mysql select query execute here

У майбутньому у вас може бути інша база даних, тоді вам не потрібно буде змінювати весь код, потрібно буде лише передати новий тип бази даних, і інший код буде працювати без змін.

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

Вихід:

Oracle Database Connection
Your oracle select query execute here

Сподіваюся, це допоможе.


1

Взагалі "фабрика" щось виробляє: у випадку з об'єктно-орієнтованим програмуванням "фабричний шаблон дизайну" створює об'єкти.

Не має значення, на PHP, C # чи будь-якій іншій об’єктно-орієнтованій мові.


1

Заводський шаблон дизайну (Factory Pattern) призначений для вільного зчеплення. Як і значення заводу, дані для заводу (виробляють дані) для кінцевого користувача. Таким чином, фабрика розірвала тісну взаємозв'язок між джерелом даних та процесом даних.



0

Ця відповідь стосується іншого допису, в якому Даніель Уайт сказав використовувати фабрику для створення з'єднання MySQL із використанням фабричного шаблону.

Для підключення MySQL я б скоріше використовував одиночний шаблон, оскільки ви хочете використовувати одне і те ж з'єднання для доступу до бази даних, а не створювати іншу.


0

Класичний підхід до створення екземпляра об'єкта:

$Object=new ClassName();

PHP має можливість динамічно створювати об'єкт з імені змінної, використовуючи такий синтаксис:

$Object=new $classname;

де змінна $ classname містить ім'я класу, який потрібно створити.

Тож класичний об’єктний факторинг буде виглядати так:

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

а якщо ви викликаєте функцію getInstance ('Product'), ця фабрика створить і поверне об'єкт Product. В іншому випадку, якщо ви викликаєте функцію getInstance ('Клієнт'), ця фабрика створить і поверне об'єкт типу Клієнт (створений з класу Клієнт ()).

Більше це не потрібно, можна надіслати 'Product' або 'Customer' (точні назви існуючих класів) як значення змінної для динамічного створення:

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

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

0

Для запису, легкими словами, фабрика, як @Pindatjuh, повертає об'єкт.

Отже, яка різниця з конструктором? (це те саме)

  1. конструктор використовує власний екземпляр.
  2. Щось, що я хочу зробити щось більш просунуте, і я не хочу роздувати об'єкт (або додавати залежності).
  3. Конструктор викликається при створенні кожного екземпляра. Іноді цього не хочеться.

    Наприклад, скажімо, що кожного разу, коли я створюю об'єкт класу Account, я читаю з бази даних файл і використовую його як шаблон.

Використання конструктора:

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

Використання заводу:

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;
      }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.