Основы программирования
Паттерны проектирования: 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