Весняний РОЗПРОДАЖ

Порівняння фабрик

У цій статті ми спробуємо розібратися, чим відрізняються:

  1. Фабрика
  2. Створюючий метод
  3. Статичний фабричний метод
  4. Проста фабрика
  5. Фабричний метод
  6. Абстрактна фабрика

У багатьох книгах та джерелах автори дають свої визначення «фабрик». Це створює велику плутанину під час вивчення матеріалів у інтернеті.

Отже, давайте розберемося у варіаціях фабрик, аби раз і назавжди зрозуміти різницю між ними.

1. Фабрика

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

Ви можете почути слово Фабрика від інших людей, коли вони мають на увазі::

  • функцію чи метод, що створює всі об’єкти програми;
  • клас, який створює користувачів системи;
  • статичний метод, який обертає конструктор класа;
  • один із класичних фабричних патернів, наведених нижче.

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

2. Створюючий метод

Створюючий метод  — це простий метод-обгортка над викликом конструктора продукта. Виділивши створюючий метод, ви ізолюєте будь-які зміни в конструюванні продуктів із боку основного коду. Наприклад, ви можете цілком прибрати виклик конструктора зі створюючого методу, віддаючи замість нового об’єкта вже наявний.

Багато хто називає його фабричним методом лише через те, що він створює нові об’єкти. Типова логіка: «цей метод створює об’єкти, а оскільки всі фабрики щось створюють, то, значить, цей метод — фабричний». Саме це спричиняє основну плутанину між поняттям Створюючого метода та патерном Фабричний метод.

У цьому прикладі, метод next є створюючим методом:

class Number {
    private $value;

    public function __construct($value) {
        $this->value = $value;
    }

    public function next() {
        return new Number ($this->value + 1);
    }
}

3. Статичний фабричний метод

Статичний фабричний метод — варіація створюючого методу, оголошена як static. Якщо цей метод створює об’єкти свого ж класу, то, фактично, він постає як альтернативний конструктор. Це може бути корисно, якщо:

  • Необхідно створити різні за функціональністю конструктори, у яких збігалися б сигнатури (наприклад, Random(int max) і Random(int min)). Це неможливо в багатьох мовах програмування, але створивши статичний метод, ви можете обійти це обмеження.

  • Хочеться повторно використовувати готові об’єкти, замість створення нових (наприклад, патерн Одинак). Під час виклику конструктора ви завжди створюєте новий об’єкт. Це можна оминути, якщо винести виклик конструктора в новий метод. У цьому методі ви можете спочатку пошукати готовий об’єкт у якому-небудь кеші, і лише за його браком створювати новий об’єкт.

У наступному прикладі, метод load є статичним фабричним методом — він надає зручний спосіб завантажити користувача з бази даних.

class User {
    private $id, $name, $email, $phone;

    public function __construct($id, $name, $email, $phone) {
        $this->id = $id;
        $this->name = $name;
        $this->email = $email;
        $this->phone = $phone;
    }

    public static function load($id) {
        list($id, $name, $email, $phone) = DB::load_data('users', 'id', 'name', 'email', 'phone');
        $user = new User($id, $name, $email, $phone);
        return $user;
    }
}

4. Патерн Проста фабрика

Патерн Проста фабрика  — це клас, у якому є один метод із великим умовним оператором, який вибирає продукт для створення. Цей метод викликають із певним параметром, за яким визначається продукт, що необхідно створити.

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

Якщо оголосити клас простої фабрики абстрактним (Java, C#), це не зробить його тим же, що і абстрактна фабрика!

Ось приклад простої фабрики:

class UserFactory {
    public static function create($type) {
        switch ($type) {
            case 'user': return new User();
            case 'customer': return new Customer();
            case 'admin': return new Admin();
            default:
                throw new Exception('Wrong user type passed.');
        }
    }
}

Проста фабрика перебуває за крок від того, щоби стати Фабричним методом.

5. Патерн Фабричний метод

Патерн Фабричний метод  — це структура класів, за якої підкласи можуть перевизначати тип продукта, що створюється в суперкласі.

Якщо ви маєте ієрархію продуктів і абстрактний створюючий метод, який перевизначається в підкласах, то перед вами патерн Фабричний метод.

abstract class Department {
    public abstract function createEmployee($id);

    public function fire($id) {
        $employee = $this->createEmployee($id);
        $employee->paySalary();
        $employee->dismiss();
    }
}

class ITDepartment extends Department {
    public function createEmployee($id) {
        return new Programmer($id);
    }
}

class AccountingDepartment extends Department {
    public function createEmployee($id) {
        return new Accountant($id);
    }
}

6. Патерн Абстрактна фабрика

Патерн Абстрактна фабрика  — це структура класів, яка полегшує створення сімейств продуктів.

Що таке сімейство продуктів? Наприклад, класи Транспорт + Двигун + Керування. Варіаціями цього сімейства можуть стати:

  1. Автомобіль + ДвигунВнутрішньогоЗгоряння + Кермо
  2. Літак + РеактивнийДвигун + Штурвал

Якщо у вас нема сімейств продуктів, тоді не може бути й абстрактної фабрики.

Багато хто плутає патерн абстрактна фабрика з класом простої фабрики, оголошеним як abstract, але це зовсім не одне й те ж саме!

Післямова

Тепер, коли ви остаточно розібралися в термінології, ознайомтеся з нашими описами фабричних патернів: