← Назад к вопросам

Какой паттерн использовать для создания сущности в зависимости от контекста?

1.7 Middle🔥 131 комментариев
#Архитектура и паттерны#ООП

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн "Фабрика" для создания сущностей в зависимости от контекста

Для создания сущностей в зависимости от контекста чаще всего применяется паттерн "Фабрика" (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: в современных фреймворках для управления созданием сложных объектов

Выбор паттерна зависит от конкретных требований: если нужно создавать различные сущности на основе входных параметров или контекста выполнения — фабричные паттерны являются наиболее подходящим и проверенным решением.

Какой паттерн использовать для создания сущности в зависимости от контекста? | PrepBro