В ИТ все любят умничать словами «шаблоны проектирования». Читаешь книжки — ощущение, что без них твой код вообще не имеет права жить. Но правда в том, что шаблоны — это как набор старых инструментов в гараже. Иногда достаёшь и пользуешься, а иногда понимаешь, что проще было бы забить гвоздь молотком, а не разбирать перфоратор.

Возьмём три простых зверя: Singleton, Factory и Observer. Они встречаются почти в каждом PHP-проекте, даже если ты не хотел. Да, и даже если ты считаешь себя выше этого.

Singleton

О, старина Singleton. Самый задроченный шаблон. Его задача — гарантировать, что в приложении есть ровно один объект этого класса. Всё. Никакой магии.

Где реально нужен:

  • подключение к базе (PDO, mysqli — не важно, один коннект рулит),
  • глобальные настройки,
  • иногда кэш или логгер.

Где не нужен:

  • везде остальное. Потому что потом код начинает выглядеть так, будто у тебя глобальная переменная воскресла и пошла пить твою кровь.

Пример (минимум кода, максимум смысла):

class DB {
    private static $instance;
    private function __construct() {}
    
    public static function getInstance() {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

// Использование $db = DB::getInstance();

Всё. Если ты начинаешь городить к этому 200 строк с двойными блокировками и прочей хернёй — проверь, не пишешь ли ты случайно Java.

Factory

Factory — это когда тебе надо создавать объекты, но не хочется в каждом месте писать new Dog(), new Cat(), new Whatever(). Вместо этого ты прячешь эту грязь за фабрикой.

Пример из жизни: у тебя есть сервис по работе с платёжками, и разные провайдеры. Где-то Yookassa, где-то Stripe. Код клиента должен просто сказать: «Дай мне платёжку», а не знать про все эти кишки.

interface Animal {
    public function speak();
}

class Dog implements Animal {
    public function speak() { return "Гав"; }
}

class Cat implements Animal {
    public function speak() { return "Мяу"; }
}

class AnimalFactory {
    public static function create($type) {
        switch ($type) {
            case 'dog': return new Dog();
            case 'cat': return new Cat();
            default: throw new Exception("Животное не найдено");
        }
    }
}

// Использование $animal = AnimalFactory::create('dog');
echo $animal->speak(); // "Гав" 

Фабрика полезна, когда у тебя один интерфейс, куча реализаций, и ты не хочешь, чтобы твой код знал об этом зоопарке.

Observer

Observer — это паттерн «я крикнул, все услышали». У тебя есть объект (Subject), и куча подписчиков (Observers), которые ждут, что он изменится.

Примеры:

  • Laravel Events (всё на Observer),
  • отправка писем после регистрации,
  • реакция на обновление данных (например, пользователь сменил пароль — пушнули событие).

Минимальный пример:

class Subject {
    private $observers = [];
    private $state;

    public function attach($observer) {
        $this->observers[] = $observer;
    }

    public function setState($state) {
        $this->state = $state;
        $this->notify();
    }

    public function getState() {
        return $this->state;
    }

    private function notify() {
        foreach ($this->observers as $observer) {
            $observer->update($this);
        }
    }
}

interface Observer {
    public function update(Subject $subject);
}

class Logger implements Observer {
    public function update(Subject $subject) {
        echo "Состояние изменилось: " . $subject->getState() . "\n";
    }
}

// Использование $subject = new Subject();
$subject->attach(new Logger());
$subject->setState("active"); // "Состояние изменилось: active" 

Да, это звучит как лишняя абстракция, но когда у тебя 5+ реакций на одно событие, Observer реально спасает от кучи хардкода.

Вместо вывода

Все эти паттерны — это не законы природы. Это просто старые костыли, которые помогают не утонуть в бардаке.

  • Singleton — хорош, пока не превращается в глобальные переменные с короной.
  • Factory — экономит твои нервы, когда в проекте больше одного типа сущностей.
  • Observer — норм штука, если хочешь, чтобы объекты разговаривали между собой без прямых связей.

Не надо молиться на паттерны, но и игнорировать их тоже тупо. Просто используй их как молоток, а не как религию.