Фабричний Метод (Factory Method)

Аналогія

Одна кадровичка не в змозі провести співбесіди з усіма кандидатами на всі посади. Залежно від вакансії, вона може делегувати різні етапи співбесід різним співробітникам.

Коротко

Це спосіб делегування логіки створення об'єктів (instantiation logic) дочірнім класам.

Вікіпедія

У класо-орієнтованому програмуванні (class-based programming) фабричним методом називають шаблон проектування, що породжує, використовує генеруючі методи (factory method) для вирішення проблеми створення об'єктів без вказівки для них конкретних класів. Об'єкти створюються за допомогою виклику не конструктора, а генеруючого способу, визначеного в інтерфейсі та реалізованого дочірніми класами або реалізованого в базовому класі і, опціонально, перевизначеного (overridden) похідними класами (derived classes).

Приклад

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

interface Interviewer
{
    public function askQuestions();
}

class Developer implements Interviewer
{
    public function askQuestions()
    {
        echo 'Asking about design patterns!';
    }
}

class CommunityExecutive implements Interviewer
{
    public function askQuestions()
    {
        echo 'Asking about community building';
    }
}

Тепер створимо кадровичок HiringManager. abstract class HiringManager

{

    // Фабричний метод
    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 = новий DevelopmentManager();
$devManager->takeInterview(); // Output: Запитує про шаблони проектування.

$marketingManager = new MarketingManager();
$marketingManager->takeInterview(); // Output: Запитує про створення спільноти.

Коли використовувати?

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