Какие паттерны проектирования знаешь


Паттерны проектирования (design patterns) — это универсальные, повторяемые решения типичных проблем, возникающих при проектировании архитектуры программного обеспечения. Они не являются готовым кодом, а представляют собой концепции, которые можно адаптировать под конкретную задачу. Наиболее известной классификацией паттернов является классификация, предложенная "Бандой четырёх" (Gang of Four, GoF): Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес. Они разделили паттерны на три основные категории:

1. Порождающие паттерны (Creational Patterns)

Эти паттерны связаны с созданием объектов, позволяя системе быть независимой от конкретных классов создаваемых объектов.

1.1. Singleton (Одиночка)

Обеспечивает наличие только одного экземпляра класса и предоставляет к нему глобальную точку доступа.

  • Используется, например, для логгера, подключения к БД, конфигурации.

  • Пример: Database.getInstance().

1.2. Factory Method (Фабричный метод)

Определяет интерфейс для создания объекта, но позволяет подклассам решать, какой класс инстанцировать.

  • Позволяет использовать полиморфизм при создании объектов.

  • Пример: ShapeFactory.createShape("circle").

1.3. Abstract Factory (Абстрактная фабрика)

Позволяет создавать семейства взаимосвязанных объектов, не привязываясь к конкретным классам.

  • Например, создание GUI-компонентов для разных ОС.

1.4. Builder (Строитель)

Отделяет создание сложного объекта от его представления, позволяя использовать один и тот же процесс построения для различных представлений.

  • Пример: построение HTML-документа или сложного объекта с множеством опций.

1.5. Prototype (Прототип)

Создание нового объекта путем клонирования уже существующего.

  • Используется для копирования сложных объектов.

2. Структурные паттерны (Structural Patterns)

Эти паттерны упрощают реализацию сложных структур и отношений между объектами.

2.1. Adapter (Адаптер)

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

  • Пример: USB-переходник.

2.2. Bridge (Мост)

Отделяет абстракцию от её реализации, позволяя изменять их независимо.

  • Полезен для работы с платформозависимыми реализациями.

2.3. Composite (Компоновщик)

Позволяет объединить объекты в древовидную структуру для представления иерархий.

  • Пример: дерево компонентов GUI.

2.4. Decorator (Декоратор)

Добавляет объекту новые обязанности динамически.

  • Пример: обёртка для логгирования метода или добавления функциональности.

2.5. Facade (Фасад)

Предоставляет унифицированный интерфейс к набору интерфейсов в подсистеме.

  • Упрощает доступ к сложной системе.

2.6. Flyweight (Приспособленец)

Позволяет эффективно использовать память за счёт повторного использования объектов.

  • Пример: символы в текстовом редакторе.

2.7. Proxy (Заместитель)

Представляет объект-заместитель, который контролирует доступ к другому объекту.

  • Пример: защита, кэширование, удалённый доступ.

3. Поведенческие паттерны (Behavioral Patterns)

Они определяют алгоритмы и способы взаимодействия между объектами.

3.1. Chain of Responsibility (Цепочка обязанностей)

Передаёт запрос по цепочке обработчиков, пока кто-то не обработает его.

  • Пример: обработка событий в UI.

3.2. Command (Команда)

Инкапсулирует запрос как объект, позволяя параметризовать клиентов с различными запросами.

  • Удобно для реализации undo/redo.

3.3. Interpreter (Интерпретатор)

Задаёт грамматику языка и интерпретатор предложений этого языка.

  • Пример: регулярные выражения.

3.4. Iterator (Итератор)

Предоставляет способ последовательного доступа ко всем элементам коллекции, не раскрывая её внутреннюю структуру.

  • Пример: for...of в JavaScript или foreach в Java.

3.5. Mediator (Посредник)

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

  • Пример: диспетчер сообщений в UI.

3.6. Memento (Хранитель)

Сохраняет внутреннее состояние объекта без нарушения инкапсуляции.

  • Пример: реализация откатов (undo).

3.7. Observer (Наблюдатель)

Определяет зависимость "один ко многим" между объектами, так что при изменении одного все зависят обновляются автоматически.

  • Пример: подписка на события, реактивные библиотеки.

3.8. State (Состояние)

Позволяет объекту изменять поведение при изменении его внутреннего состояния.

  • Пример: автомат с напитками.

3.9. Strategy (Стратегия)

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

  • Пример: выбор алгоритма сортировки.

3.10. Template Method (Шаблонный метод)

Определяет основу алгоритма в методе, оставляя реализацию некоторых шагов подклассам.

  • Пример: шаги обработки данных, где часть шагов общие.

3.11. Visitor (Посетитель)

Позволяет добавить операцию к объекту без изменения самого объекта.

  • Используется в компиляторах, парсерах AST.

Другие паттерны, вне GoF

  • MVC (Model-View-Controller) — разделение данных, логики и представления.

  • MVVM (Model-View-ViewModel) — популярен в SwiftUI, Android, WPF.

  • Singleton Scope — особенно актуален в Spring и DI-контейнерах.

  • Dependency Injection (DI) — внедрение зависимостей через конструкторы или свойства.

  • Service Locator — глобальный реестр зависимостей (менее предпочтителен).

  • Repository, Unit of Work — используются в архитектуре доступа к данным.

Эти паттерны формируют основу для архитектурных решений в разработке, особенно в масштабных и поддерживаемых проектах. Их знание важно для понимания чужого кода, совместной работы в команде и грамотного проектирования программных систем.