Теперь, когда мы уже примерно понимаем, что такое паттерны проектирования и зачем они нужны, давайте разберёмся, какие вообще бывают паттерны.
Их существует довольно много, но абсолютное большинство удобно разделить на три большие группы: порождающие, структурные и поведенческие.
Эти паттерны отвечают за создание объектов.
Казалось бы, что тут сложного — вызвали new, получили объект, идём дальше. Но когда проект растёт, простого new становится мало.
Иногда нужно, чтобы:
объект создавался по определённым правилам;
детали его устройства были скрыты;
можно было гибко управлять тем, что именно создаётся и каким образом.
Вот здесь и приходят на помощь порождающие паттерны.
Они делают процесс создания объектов контролируемым, гибким и предсказуемым.
Примеры:
- Singleton (Одиночка) — гарантирует, что в программе есть только один экземпляр объекта (например, логгер или менеджер настроек).
- Factory Method (Фабричный метод) — создаёт объекты через общий интерфейс, не привязываясь к конкретным классам.
- Abstract Factory (Абстрактная фабрика) — создаёт целые семьи связанных объектов, работающих вместе.
- Builder (Строитель) — помогает пошагово собирать сложные объекты.
- Prototype (Прототип) — создаёт новые объекты копированием существующих.
Если говорить максимально простыми словами:
Порождающие паттерны — это про то, как именно мы создаём объекты и кто принимает решение о том, что именно будет создано.
Мы уже знаем, что порождающие паттерны помогают нам создавать объекты — управлять тем, как именно они появляются в программе.
Но создание — это только начало. Потом все эти объекты нужно связать между собой, заставить их работать как единая система, обмениваться данными и не мешать друг другу.
И вот здесь появляются структурные паттерны.
Эти паттерны помогают строить связи между классами и объектами.
Они отвечают на вопрос:
«Как правильно соединить части программы, чтобы всё работало вместе и не превратилось в хаос?»
Иногда требуется объединить несколько объектов, добавить им новые возможности или спрятать за простым интерфейсом какую-то сложную внутренность.
И во всех таких случаях структурные паттерны — наши лучшие помощники.
Примеры:
- Adapter (Адаптер) — превращает один интерфейс в другой, чтобы несовместимые классы могли работать вместе.
- Decorator (Декоратор) — добавляет объекту новое поведение, не изменяя его исходный код.
- Facade (Фасад) — предоставляет простой интерфейс к сложной подсистеме, скрывая детали её работы.
- Composite (Компоновщик) — объединяет объекты в древовидные структуры, чтобы с ними можно было работать единообразно.
- Proxy (Заместитель) — подменяет реальный объект, добавляя дополнительную логику (например, кэширование или контроль доступа).
Если коротко:
Структурные паттерны — это про то, как правильно соединить объекты между собой. Сама программа — это не просто набор объектов, стоящих рядом.
Эти объекты должны взаимодействовать, обмениваться данными, реагировать на действия друг друга.
Кто-то выполняет действие, кто-то отвечает, кто-то наблюдает и ждёт сигнала — всё это и есть поведение системы.
И именно с этой стороной работы кода нам помогают поведенческие паттерны.
Эти паттерны отвечают за то, как объекты взаимодействуют и обмениваются информацией.
Они помогают организовать, кто что делает, кто кого вызывает, и каким образом передаются данные или события.
Примеры:
- Strategy (Стратегия) — позволяет гибко менять поведение объекта, подставляя разные алгоритмы (мы уже встречались с этим паттерном).
- Observer (Наблюдатель) — уведомляет другие объекты об изменениях состояния (по сути, система подписок и событий).
- Command (Команда) — превращает действие в объект, позволяя откладывать выполнение, отменять или комбинировать команды.
- State (Состояние) — позволяет объекту менять своё поведение в зависимости от внутреннего состояния.
- Iterator (Итератор) — даёт возможность перебирать элементы коллекции, не зная её внутреннего устройства.
Если совсем коротко:
Поведенческие паттерны — это про то, как объекты общаются между собой и координируют работу. Само собой, мы не просто так всё это обсудили.
Очень полезно понимать, к какому типу относится паттерн, потому что это сразу даёт вам контекст и направление мысли.
Например, когда мы начнём разбирать паттерн «Прототип», даже если вы пока не знаете, что именно он делает, но слышите, что он относится к порождающим паттернам, — вы уже можете предположить:
Точно так же, если паттерн относится к поведенческим, вы понимаете, что он будет касаться логики взаимодействия и управления поведением объектов.
А если он из группы структурных — значит, речь пойдёт о связях между частями системы, о том, как объекты организованы и соединены друг с другом.
Такое понимание помогает гораздо быстрее ориентироваться в архитектуре, узнавать паттерны в чужом коде и даже интуитивно выбирать правильный подход — не заучивая механически, а понимая смысл и назначение каждого паттерна.
Порождающие паттерны (Creational) — отвечают за создание объектов: как именно они появляются и кто принимает решение о том, что будет создано.
Структурные паттерны (Structural) — помогают правильно соединить объекты между собой, строить связи между классами.
Поведенческие паттерны (Behavioral) — отвечают за взаимодействие объектов, передачу данных и координацию работы.