Отличие создания объекта при помощи фабричного метода от создания объекта реализующего конкретный интерфейс напрямую

100
06 июля 2021, 09:30

Есть реализация фабричного метода:

    interface Interviewer
    {
        public function askQuestions();
    }
    class Developer implements Interviewer
    {
        public function askQuestions()
        {
            echo 'Спросить о шаблонах проектирования';
        }
    }
    class CommunityExecutive implements Interviewer
    {
        public function askQuestions()
        {
            echo 'Спросить об общественном строительстве';
        }
    }
abstract class HiringManager
{
    // Factory method
    abstract public function makeInterviewer(): Interviewer;
    public function takeInterview()
    {
        $interviewer = $this->makeInterviewer();
        $interviewer->askQuestions();
    }
}
class DevelopmentManager extends HiringManager
{
    public function makeInterviewer(): Interviewer
    {
        return new Developer();
    }
}
class MarketingManager extends HiringManager
{
    public function makeInterviewer(): Interviewer
    {
        return new CommunityExecutive();
    }
}

После чего можно использовать:

$devManager = new DevelopmentManager();
$devManager->takeInterview(); // Спросить о шаблонах проектирования
$marketingManager = new MarketingManager();
$marketingManager->takeInterview(); // Спросить об общественном строительстве

Но я могу и так использовать:

$developer = new Developer();
developer.askQuestions() // Спросить о шаблонах проектирования
$сommunityExecutive = new CommunityExecutive();
сommunityExecutive.askQuestions()//Спросить об общественном строительстве

т.к и Developer и CommunityExecutive реализуют один интерфейс. Тогда зачем мне писать эту большую конструкцию с фабричным методом?

Answer 1

Если быть точным, то в вашем примере используется не фабричный метод а AbstractFactory. Но не суть.

Есть несколько преимуществ использования данного шаблона по сравнению с созданием объекта напрямую через new.

  1. Вы имеете больше контроля над созданием объекта и если захотите изменить реализацию, то достаточно будет поменять с new CommunityExecutive() на new Developer() в одном месте
  2. Иногда создание объекта довольно трудоемко - требуется передавать куча всяких параметров в конструктор. Тащить все эти параметры каждый раз в то место, где вы хотите создать объект не удобно. Вместо этого создают реализацию абстрактной фабрики в которой уже есть все нужные объекты и передают уже ее в качестве параметра. Например:
void doSmth(String name, int age, String city){
     Person p = new GoodPerson(name, age, city);
}

Или так:

void doSmth(GoodPersonFactory factory){
     Person p = factory.create();
}
  1. Так же иногда возникает потребность в создании не одного а нескольких разных объектов которые логически связанны между собой. И хочется объединить, сгруппировать их создание в одном месте. Например:
interface PizzeriaFactory{
   Pizza createPizza(Ingredients ingredients);
   Ingredients createIngredients();
}
class ItalianPizzeriaFactory{
   Pizza createPizza(Ingredients ingredients){
     return new ItalianPizza(ingredients)
   }
   Ingredients createIngredients(){
     return new ItalianIngredients(SHEESE, TOMATO, SALADE)
   }
}
READ ALSO
Как избавиться от большого количества запросов к бд, при попытке вытянуть связи через expand в Yii2?

Как избавиться от большого количества запросов к бд, при попытке вытянуть связи через expand в Yii2?

Разрабатываю RESTful API на фреймворке Yii2На данный момент делаю вторую версию API v2

90
Перевод разницы во времени в часы PHP

Перевод разницы во времени в часы PHP

Как посчитать разницу $gotime - $cometime в (int) часах?

108
Работа с preg_replace

Работа с preg_replace

Прошу помочь с использованием функции preg_replace

100
Добавить изображение в анонсы элемента

Добавить изображение в анонсы элемента

Доброго времени суток Подскажите пожалуйста как добавить image в Анонсы элемента? Я делаю так:

114