Введение в паттерны проектирования
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 90 из 104.
Шаблоны проектирования — это проверенные, повторно используемые решения распространённых проблем, возникающих при проектировании программного обеспечения. Это не код, который можно просто скопировать, а шаблоны или схемы, описывающие, как элегантно структурировать классы и объекты для решения конкретных задач.
Эта концепция получила широкое распространение благодаря книге «Банды четырёх» (GoF), опубликованной в 1994 году и описывающей 23 фундаментальных шаблона. Обычно эти шаблоны делят на три категории:
| Категория | Назначение | Примеры |
|---|---|---|
| Порождающие | Механизмы создания объектов | Одиночка, Фабрика, Строитель |
| Структурные | Композиция классов и объектов | Адаптер, Декоратор, Компоновщик |
| Поведенческие | Взаимодействие объектов и распределение обязанностей | Наблюдатель, Стратегия, Команда |
Зачем изучать шаблоны проектирования? Они создают общий словарь для разработчиков — фраза «используй здесь фабрику» мгновенно передаёт сложную идею. Они также помогают не изобретать решения заново и делают ваш код более гибким и удобным для сопровождения.
В C++ шаблоны проектирования используют возможности ООП, которые вы уже изучили: наследование, полиморфизм, абстрактные классы и шаблоны. В следующих уроках вы реализуете несколько важных шаблонов и поймёте, когда каждый из них подходит для решения задачи.
Задание
ЛегкоСоздай простой классификатор шаблонов проектирования, который продемонстрирует твоё понимание трёх категорий шаблонов проектирования. Ты создашь систему, которая принимает название шаблона и определяет, к какой категории он относится: Creational, Structural или Behavioral, а также выводит краткое описание назначения этой категории.
Твой код будет распределён по трём файлам:
PatternCategory.h: Определи абстрактный базовый класс с именемPatternCategory, представляющий категорию шаблонов проектирования. В нём должны быть:- Чисто виртуальный метод
getName(), возвращающий название категории в виде строки - Чисто виртуальный метод
getPurpose(), возвращающий описание того, для чего нужны шаблоны этой категории - Виртуальный деструктор
Затем создай три производных класса, наследующих
PatternCategory:CreationalCategory: возвращает название"Creational"и назначение"Object creation mechanisms"StructuralCategory: возвращает название"Structural"и назначение"Class and object composition"BehavioralCategory: возвращает название"Behavioral"и назначение"Object interaction and responsibility"
- Чисто виртуальный метод
PatternClassifier.h: Создай классPatternClassifier, который определяет, к какой категории относится заданный шаблон.В классификаторе должен быть метод
classify, который принимает название шаблона (строку) и возвращает указатель на соответствующийPatternCategory. Используй умные указатели (std::unique_ptr) для управления памятью.Классификатор должен распознавать следующие шаблоны:
- Creational:
Singleton,Factory,Builder - Structural:
Adapter,Decorator,Composite - Behavioral:
Observer,Strategy,Command
Если название шаблона не распознано, верни
nullptr.- Creational:
main.cpp: Считай одно входное значение: название шаблона проектирования.Создай
PatternClassifierи используй его, чтобы классифицировать введённый шаблон. Если шаблон распознан, выведи:[PatternName] is a [CategoryName] pattern Purpose: [CategoryPurpose]Если шаблон не распознан, выведи:
Unknown pattern: [PatternName]
Например, при вводе Singleton:
Singleton is a Creational pattern
Purpose: Object creation mechanismsПри вводе Observer:
Observer is a Behavioral pattern
Purpose: Object interaction and responsibilityПри вводе Proxy:
Unknown pattern: ProxyЭто задание закрепляет три категории шаблонов проектирования и позволяет попрактиковаться в наследовании, полиморфизме и использовании умных указателей — всё это понятия, которые ты уже освоил. Структура из нескольких файлов отражает то, как в реальных проектах организуют связанные классы.
Попробуйте сами
#include <iostream>
#include <string>
#include "PatternClassifier.h"
int main() {
// Считайте название паттерна
std::string patternName;
std::cin >> patternName;
// TODO: Создайте экземпляр PatternClassifier
// TODO: Используйте классификатор, чтобы определить категорию введённого паттерна
// TODO: Если паттерн распознан, выведите:
// "[PatternName] is a [CategoryName] pattern"
// "Purpose: [CategoryPurpose]"
// TODO: Если паттерн не распознан (nullptr), выведите:
// "Unknown pattern: [PatternName]"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++