Какой паттерн использовать для создания сущности в зависимости от контекста?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Паттерн "Фабрика" для создания сущностей в зависимости от контекста
Для создания сущностей в зависимости от контекста чаще всего применяется паттерн "Фабрика" (Factory Pattern) или его вариации — "Абстрактная фабрика" (Abstract Factory) и "Фабричный метод" (Factory Method). Выбор конкретного паттерна зависит от сложности контекста и структуры создаваемых объектов.
Основные паттерны и их применение
1. Фабричный метод (Factory Method)
Используется, когда логика создания объектов зависит от подклассов. Создание делегируется дочерним классам.
interface Product {
public function operation(): string;
}
class ConcreteProductA implements Product {
public function operation(): string {
return 'Product A';
}
}
class ConcreteProductB implements Product {
public function operation(): string {
return 'Product B';
}
}
abstract class Creator {
abstract public function factoryMethod(): Product;
public function someOperation(): string {
$product = $this->factoryMethod();
return "Creator: " . $product->operation();
}
}
class ConcreteCreatorA extends Creator {
public function factoryMethod(): Product {
return new ConcreteProductA();
}
}
class ConcreteCreatorB extends Creator {
public function factoryMethod(): Product {
return new ConcreteProductB();
}
}
// Использование
function clientCode(Creator $creator) {
echo $creator->someOperation();
}
clientCode(new ConcreteCreatorA()); // Creator: Product A
clientCode(new ConcreteCreatorB()); // Creator: Product B
2. Абстрактная фабрика (Abstract Factory)
Подходит для создания семейств связанных объектов без указания их конкретных классов. Особенно полезен при работе с различными платформами или темами.
interface AbstractFactory {
public function createButton(): Button;
public function createModal(): Modal;
}
class LightThemeFactory implements AbstractFactory {
public function createButton(): Button {
return new LightButton();
}
public function createModal(): Modal {
return new LightModal();
}
}
class DarkThemeFactory implements AbstractFactory {
public function createButton(): Button {
return new DarkButton();
}
public function createModal(): Modal {
return new DarkModal();
}
}
// Использование
function renderUI(AbstractFactory $factory) {
$button = $factory->createButton();
$modal = $factory->createModal();
$button->render();
$modal->show();
}
$theme = 'dark';
$factory = $theme === 'dark' ? new DarkThemeFactory() : new LightThemeFactory();
renderUI($factory);
3. Простая фабрика (Simple Factory)
Упрощенный вариант, где один класс инкапсулирует логику создания объектов.
class UserFactory {
public static function create(string $type): User {
return match($type) {
'admin' => new AdminUser(),
'manager' => new ManagerUser(),
'customer' => new CustomerUser(),
default => throw new InvalidArgumentException('Unknown user type'),
};
}
}
// Использование
$user = UserFactory::create($_POST['role']);
Критерии выбора паттерна
- Фабричный метод: когда заранее неизвестно, объекты каких классов нужно создавать, или когда создание делегируется подклассам
- Абстрактная фабрика: когда система должна быть независимой от способа создания объектов и должна конфигурироваться одним из нескольких семейств объектов
- Простая фабрика: когда логика создания проста и не требует сложной иерархии
Преимущества использования фабрик
- Инкапсуляция логики создания: код создания объектов сосредоточен в одном месте
- Гибкость: легко добавлять новые типы сущностей без изменения клиентского кода
- Упрощение тестирования: можно легко подменять создаваемые объекты моками или стабами
- Соблюдение принципа открытости/закрытости: система открыта для расширения, но закрыта для модификации
Практический пример с контекстом платежных систем
class PaymentFactory {
public static function create(string $gateway, array $config): PaymentProcessor {
return match($gateway) {
'stripe' => new StripeProcessor($config['api_key']),
'paypal' => new PayPalProcessor($config['client_id'], $config['secret']),
'yookassa' => new YooKassaProcessor($config['shop_id'], $config['secret_key']),
default => throw new PaymentGatewayException("Unsupported gateway: $gateway"),
};
}
}
// Использование в зависимости от контекста
$context = determinePaymentContext(); // Может зависеть от страны, суммы, валюты
$processor = PaymentFactory::create($context['gateway'], $context['config']);
$result = $processor->charge($amount, $currency);
Альтернативные подходы
В некоторых случаях могут применяться:
- Строитель (Builder): когда создание объекта состоит из множества шагов
- Прототип (Prototype): когда создание объекта через клонирование дешевле, чем через конструктор
- Dependency Injection Container: в современных фреймворках для управления созданием сложных объектов
Выбор паттерна зависит от конкретных требований: если нужно создавать различные сущности на основе входных параметров или контекста выполнения — фабричные паттерны являются наиболее подходящим и проверенным решением.