Сравнение фабрик
В этой статье мы попробуем разобраться чем отличаются:
- Фабрика
- Создающий метод
- Статический фабричный метод
- Простая фабрика
- Фабричный метод
- Абстрактная фабрика
Во многих книгах и источниках определения «фабрик» даётся авторами по-своему. Это создаёт большую путаницу при чтении материалов в интернете.
Итак, давайте разберёмся в вариациях фабрик, чтобы раз и навсегда понять разницу между ними.
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. Паттерн Абстрактная фабрика
Паттерн Абстрактная фабрика – это устройство классов, облегчающее создание семейств продуктов.
Что такое семейство продуктов? Например, классы Транспорт
+ Двигатель
+ Управление
. Вариациями этого семейства могут стать:
Автомобиль
+ДвигательВнутренннегоСгорания
+Руль
Самолет
+РеактивныйДвигатель
+Штурвал
Если у вас нет семейств продуктов, значит не может быть и абстрактной фабрики.
Многие путают паттерн абстрактная фабрика с классом простой фабрики, объявленным как abstract
, но это далеко не одно и то же!
Послесловие
Теперь, когда вы окончательно разобрались в терминологии, почитайте наши описания фабричных паттернов: