Что такое фабричный шаблон проектирования в 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находится класс, который мы используем для хранения наших данных. Теперь для этого класса, допустим, мы используем сеанс для хранения наших данных. Завод будет выглядеть так:

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, где в classZ вы бы использовали фабричный метод? По сути, вы по-прежнему создаете экземпляр класса (classZ) внутри класса (classA), что означает отсутствие тестирования. например, кажется, что factory - это просто загрузка кода, которую нужно выполнять с 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

Шаблон проектирования Factory очень хорош, когда вы имеете дело с несколькими ресурсами и хотите реализовать абстракцию высокого уровня.

Давайте разберем это на разные разделы.

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

Ему / ей просто нужно беспокоиться об использовании ваших методов класса.

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

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

}

Ваш класс Factory позаботится о создании объекта для подключения к базе данных.

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

Этот ответ относится к другому сообщению, в котором Дэниел Уайт сказал использовать factory для создания соединения MySQL с использованием шаблона factory.

Для подключения к 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 ('Customer'), эта фабрика создаст и вернет объект типа Customer (созданный из класса Customer ()).

В этом больше нет необходимости, можно отправить '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.