Какие паттерны проектирования вы знаете и применяли?

«Какие паттерны проектирования вы знаете и применяли?» — вопрос из категории Паттерны, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В своей практике на PHP я чаще всего применяю следующие паттерны:

1. Singleton (Одиночка) Использовал для глобального доступа к конфигурации или подключению к базе данных, чтобы избежать множественных инстансов.

class DatabaseConnection {
    private static ?self $instance = null;
    private function __construct() { /* ... */ }
    private function __clone() {}

    public static function getInstance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}
// Использование
$db = DatabaseConnection::getInstance();

2. Factory (Фабрика) Применял для создания семейства связанных объектов, например, разных типов уведомлений (Email, SMS, Push).

interface Notification {
    public function send(string $message): void;
}

class NotificationFactory {
    public static function create(string $type): Notification {
        return match($type) {
            'email' => new EmailNotification(),
            'sms' => new SmsNotification(),
            default => throw new InvalidArgumentException('Unknown notification type')
        };
    }
}

3. Strategy (Стратегия) Использовал для инкапсуляции различных алгоритмов сортировки или способов оплаты (CreditCard, PayPal), которые можно подменять в рантайме.

interface PaymentStrategy {
    public function pay(float $amount): bool;
}

class Order {
    private PaymentStrategy $paymentStrategy;
    public function setPaymentStrategy(PaymentStrategy $strategy): void {
        $this->paymentStrategy = $strategy;
    }
    public function processPayment(float $amount): bool {
        return $this->paymentStrategy->pay($amount);
    }
}

4. Repository (Репозиторий) Активно применяю в Laravel-проектах для абстракции доступа к данным, что упрощает тестирование и смену источника данных.

// AppRepositoriesUserRepository.php
class UserRepository {
    public function findById(int $id): ?User {
        return User::find($id);
    }
    public function getAllActive(): Collection {
        return User::where('is_active', true)->get();
    }
}

Также сталкивался и применял Observer (для событийной модели), Decorator (для расширения функциональности) и Adapter (для интеграции со сторонними API).