Глянь мой новый курс по Git! Привет! Глянь мой новый курс по Git! Привет! Глянь мой новый курс по Git на GitByBit.com! Привет! Хочешь круто подтянуть Git? Глянь мой новый курс на GitByBit.com!

Сравнение фабрик

В этой статье мы попробуем разобраться чем отличаются:

  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, но это далеко не одно и то же!

Послесловие

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