Абстрактна фабрика (Abstract Factory)
Аналогія
Повернемося, наприклад, з дверима з «Простої фабрики». Залежно від своїх потреб ви можете купити дерев'яні двері в одному магазині, сталеві - в іншому, пластикові - в третьому. Для монтажу вам знадобляться різні фахівці: дерев'яних дверей потрібен тесляр, сталевий - зварювальник, пластиковий - спеціаліст з ПВХ-профілів.
Коротко Це фабрика фабрик. Тобто фабрика, що групує індивідуальні, але взаємозалежні/взаємозалежні фабрики без зазначення їм конкретних класів.
Вікіпедія
Шаблон «Абстрактна фабрика» визначає метод інкапсулювання групи індивідуальних фабрик, об'єднаних певною темою, без зазначення їм конкретних класів.
Приклад
Створимо інтерфейс Door та кілька реалізацій для нього.
interface Door
{
public function getDescription();
}
class WoodenDoor implements Door
{
public function getDescription()
{
echo 'I am a wooden door';
}
}
class IronDoor implements Door
{
public function getDescription()
{
echo 'I am an iron door';
}
}
Тепер нам потрібні фахівці із встановлення кожного виду дверей.
interface DoorFittingExpert
{
public function getDescription();
}
class Welder implements DoorFittingExpert
{
public function getDescription()
{
echo 'I can only fit iron doors';
}
}
class Carpenter implements DoorFittingExpert
{
public function getDescription()
{
echo 'I can only fit wooden doors';
}
}
Ми отримали абстрактну фабрику, яка дозволяє створювати сімейства об'єктів чи взаємопов'язані об'єкти. Тобто фабрика дерев'яних дверей створить дерев'яні двері та людину для її монтажу, фабрика сталевих дверей – сталеві двері та відповідного спеціаліста тощо.
interface DoorFactory
{
public function makeDoor(): Door;
public function makeFittingExpert(): DoorFittingExpert;
}
// Фабрика дерев'яних дверей повертає тесляр і дерев'яні двері
class WoodenDoorFactory implements DoorFactory
{
public function makeDoor(): Door
{
return new WoodenDoor();
}
public function makeFittingExpert(): DoorFittingExpert
{
return new Carpenter();
}
}
// Фабрика сталевих дверей повертає сталеві двері та зварювальника
class IronDoorFactory implements DoorFactory
{
public function makeDoor(): Door
{
return new IronDoor();
}
public function makeFittingExpert(): DoorFittingExpert
{
return new Welder();
}
}
Використання:
$woodenFactory = New WoodenDoorFactory();
$door = $woodenFactory->makeDoor();
$expert = $woodenFactory->makeFittingExpert();
$door->getDescription(); // Output: Я дерев'яні двері
$expert->getDescription(); // Output: Я можу встановлювати лише дерев'яні двері
// Same for Iron Factory
$ironFactory = новий IronDoorFactory();
$door = $ironFactory->makeDoor();
$expert = $ironFactory->makeFittingExpert();
$door->getDescription(); // Output: Я сталеві двері
$expert->getDescription(); // Output: Я можу встановлювати лише сталеві двері
Тут фабрика дерев'яних дверей інкапсулювала carpenter та wooden door, фабрика сталевих дверей – iron door and welder. Тобто можна бути впевненими, що для кожного зі створених дверей ми отримаємо правильного спеціаліста.
Коли використовувати?
Коли у вас є зв'язки з не найпростішою логікою створення (creation logic).