Основы программирования

Паттерны проектирования: Singleton, Factory, Observer

Паттерны проектирования - это «язык» между разработчиками. Когда говорят 'это Observer', все сразу понимают архитектуру. React hooks, Vue reactivity, Node.js EventEmitter, Django signals - всё это Observer.

  • Node.js EventEmitter - Observer: http.request.on('data', ...), fs.watch()
  • DOM события: document.addEventListener('click', ...) - чистый Observer
  • Django ORM: post_save, pre_delete - сигналы = Observer
  • React: useState - Observable состояние с автоматическим ре-рендером

Предварительные знания

  • ООП: классы, инстансы, методы, наследование, инкапсуляция
  • Полиморфизм и интерфейсы (или Protocol/Abstract Base Class в Python)
  • Функции первого класса: передавать функции как аргументы, возвращать из других функций
  • Объекты и классы
  • Функции

От Кристофера Александера к Gang of Four и обратно к функциям

Идея паттернов пришла в программирование из архитектуры зданий. Кристофер Александер в 1977 году выпустил книгу A Pattern Language: каталог из 253 решений для городов, домов и комнат. Кент Бек и Уорд Каннингем прочитали её и в 1987 году на конференции OOPSLA представили доклад Using Pattern Languages for Object-Oriented Programs, где впервые перенесли идею каталога повторяющихся решений в код на Smalltalk. Через семь лет, в 1994, Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес (Gang of Four, GoF) выпустили книгу Design Patterns: Elements of Reusable Object-Oriented Software. 23 паттерна разделены на три группы: порождающие (Singleton, Factory, Builder), структурные (Adapter, Decorator, Facade) и поведенческие (Observer, Strategy, Command). Книга стала каноном объектно-ориентированного дизайна в Java, C++, C# на 20 лет. В 1996 Питер Норвиг прочитал лекцию Design Patterns in Dynamic Languages: он показал, что в Lisp и Python 16 из 23 паттернов GoF либо исчезают как отдельные конструкции, либо вырождаются в одну функцию. Singleton превращается в модуль, Strategy в функцию, Command в замыкание. В функциональных языках появились свои паттерны: railroad-oriented programming (Скотт Влашин, F#), monad transformers в Haskell. Книга Влашина Domain Modeling Made Functional 2018 года предложила альтернативный каталог для FP. Сегодня GoF учат, но больше как словарь для разговоров о коде, чем как обязательный набор рецептов.

Singleton: единственный экземпляр

**Singleton** гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему. Классические примеры: логгер, конфиг, пул соединений с БД.

**Когда НЕ использовать Singleton:** Если состояние нужно сбрасывать в тестах, Singleton становится проблемой - тест А загрязняет состояние теста Б. Лучше передавать зависимость явно (DI - Dependency Injection).

В чём главная проблема Singleton в тестируемом коде?

Factory Method: создание без привязки к классу

**Factory Method** - паттерн, при котором метод создания объекта выносится в отдельный метод или класс. Это позволяет подклассам решать, какой класс инстанциировать.

Какой принцип SOLID реализует Factory Method?

Observer: подписка на события

**Observer** (Наблюдатель) - объект (Subject) ведёт список подписчиков и уведомляет их при изменении состояния. Основа event-driven архитектуры, DOM-событий и reactive-фреймворков.

Паттерны GoF - универсальные рецепты. Чем больше Singleton, Factory, Observer в коде, тем профессиональнее проект.

Паттерны - это словарь для описания решений, а не цель проектирования. В Python большинство GoF-паттернов вырождаются: Singleton заменяется модулем, Factory - функцией, Observer - встроенным asyncio.Event. Применять паттерн стоит только когда без него код становится менее ясным.

Книга GoF писалась под C++/Smalltalk 1994 года, где не было first-class функций, замыканий, метаклассов. В современных динамических языках половина паттернов - это обходные пути ограничений, которых больше нет. Pattern-driven design без понимания зачем порождает over-engineered код, который сложнее, чем проблема, которую он решает.

В чём отличие Observer от прямого вызова методов?

Ключевые идеи

  • Singleton: один экземпляр, глобальный доступ. Осторожно с тестами!
  • Factory Method: создание объектов без привязки к конкретному классу → OCP
  • Observer: Publisher/Subscriber - слабая связанность через события
  • Паттерны - инструменты, а не догмы: выбирай по задаче
  • Антипаттерн: применять паттерн там, где хватает простого кода

Что дальше

Паттерны помогают в рефакторинге и тестировании:

  • Рефакторинг — Паттерны - конечный результат многих рефакторингов
  • Тестирование — Factory и DI делают код тестируемым

Вопросы для размышления

  • Когда Singleton превращается в антипаттерн? Придумайте пример из реального проекта.
  • Чем Abstract Factory отличается от Factory Method? В каких случаях нужна «фабрика фабрик»?
  • Observer и Promise/async - в чём разница архитектурно?

Связанные уроки

  • prog-12-objects — Паттерны строятся поверх ООП: инкапсуляции и полиморфизма
  • prog-14-refactoring — Паттерны - инструмент рефакторинга и улучшения структуры
  • plt-01-paradigms — Паттерны зависят от парадигмы: ООП vs FP дают разные решения
  • sd-10-microservices — Паттерны Gang of Four живут внутри каждого микросервиса
  • ds-01-arrays
Паттерны проектирования: Singleton, Factory, Observer

0

1

Войти