Абстрактная фабрика (Abstract Factory) паттерн
📌 Суть
Абстрактная фабрика — это паттерн проектирования, который предоставляет интерфейс для создания семейства взаимосвязанных объектов без указания их конкретных классов.
Если обычная фабрика создает один объект — то абстрактная фабрика создает набор объектов, которые логически связаны и могут взаимодействовать друг с другом.
📦 Когда нужен этот паттерн?
Когда у тебя есть несколько реализаций целой системы или под-системы, и тебе нужно легко переключаться между ними.
🎯 Пример из жизни (Laravel Style)
Представь, ты делаешь систему уведомлений, которая может работать в разных каналах: email, sms, slack.
Каждый канал может состоять из нескольких компонентов:
-
Генератор шаблона
-
Отправщик
-
Логгер
И ты хочешь создать всё это в рамках одного семейства объектов.
Интерфейсы
interface NotificationSenderInterface {
public function send(string $to, string $message): bool;
}
interface TemplateRendererInterface {
public function render(string $template, array $data): string;
}
Реализации (Email)
class EmailSender implements NotificationSenderInterface {
public function send(string $to, string $message): bool {
// логика отправки email
return true;
}
}
class EmailTemplateRenderer implements TemplateRendererInterface {
public function render(string $template, array $data): string {
// подстановка данных в шаблон
return "Email: " . strtr($template, $data);
}
}
Реализации (SMS)
class SmsSender implements NotificationSenderInterface {
public function send(string $to, string $message): bool {
// логика отправки sms
return true;
}
}
class SmsTemplateRenderer implements TemplateRendererInterface {
public function render(string $template, array $data): string {
return "SMS: " . strtr($template, $data);
}
}
Абстрактная фабрика
interface NotificationFactoryInterface {
public function makeSender(): NotificationSenderInterface;
public function makeRenderer(): TemplateRendererInterface;
}
Конкретные фабрики
class EmailNotificationFactory implements NotificationFactoryInterface {
public function makeSender(): NotificationSenderInterface {
return new EmailSender();
}
public function makeRenderer(): TemplateRendererInterface {
return new EmailTemplateRenderer();
}
}
class SmsNotificationFactory implements NotificationFactoryInterface {
public function makeSender(): NotificationSenderInterface {
return new SmsSender();
}
public function makeRenderer(): TemplateRendererInterface {
return new SmsTemplateRenderer();
}
}
Использование
function notify(NotificationFactoryInterface $factory, string $to, string $template, array $data)
{
$sender = $factory->makeSender();
$renderer = $factory->makeRenderer();
$message = $renderer->render($template, $data);
$sender->send($to, $message);
}
// Используем Email
$factory = new EmailNotificationFactory();
notify($factory, 'user@example.com', 'Привет, {{name}}', ['{{name}}' => 'Андрей']);
// Используем SMS
$factory = new SmsNotificationFactory();
notify($factory, '+71234567890', 'Привет, {{name}}', ['{{name}}' => 'Анна']);
Laravel-контекст
В Laravel ты можешь:
-
Создавать NotificationFactory как сервис, регистрировать в ServiceProvider.
-
Инъецировать нужную фабрику в зависимости от контекста (например, в зависимости от роли пользователя или источника запроса).
-
Применять
Service Container, чтобы всё было прозрачно и гибко.
app()->bind(NotificationFactoryInterface::class, function () {
return match (config('notification.driver')) {
'email' => new EmailNotificationFactory(),
'sms' => new SmsNotificationFactory(),
default => throw new RuntimeException('Invalid notification driver'),
};
});
Отличия от обычной фабрики
| Критерий | Обычная фабрика | Абстрактная фабрика |
|---|---|---|
| Создаёт | Один объект | Набор логически связанных объектов |
| Интерфейс | Один метод make() |
Несколько методов makeSender(), makeRenderer() и т.д. |
| Когда использовать | Простая логика создания | Семейства компонентов, которые работают вместе |
| Пример в Laravel | Model::factory() |
Каналы уведомлений, драйверы API, UI-компоненты |