Введение в паттерны проектирования
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 90 из 104.
design patterns — это проверенные, повторно используемые решения распространённых проблем, возникающих при проектировании программного обеспечения. Это не код, который можно скопировать напрямую, а шаблоны или чертежи, описывающие, как структурировать class и object, чтобы элегантно решать конкретные задачи.
Концепция стала популярной благодаря «Банде четырёх» (GoF) и их книге 1994 года, в которой были систематизированы 23 фундаментальных шаблона. Обычно эти шаблоны объединяют в три категории:
| Категория | Назначение | Примеры |
|---|---|---|
| Creational | механизмы создания Object | Singleton, Factory, Builder |
| Structural | композиция Class и object | Adapter, Decorator, Composite |
| Behavioral | взаимодействие Object и ответственность | Observer, Strategy, Command |
Зачем изучать design patterns? Они обеспечивают общий словарь для разработчиков — фраза «используйте Factory здесь» мгновенно передаёт сложную идею. Они также помогают не изобретать решения заново и делают ваш код более гибким и удобным в сопровождении.
В C++ шаблоны проектирования используют уже изученные тобой возможности OOP: наследование, полиморфизм, абстрактные классы и шаблоны. В следующих уроках ты реализуешь несколько важных patterns и поймёшь, когда каждый из них является подходящим инструментом для решения задачи.
Задание
ЛегкоДавайте создадим простой классификатор паттернов, который продемонстрирует ваше понимание трёх категорий паттернов проектирования. Вы создадите систему, которая принимает имя паттерна и определяет, к какой категории он относится: Creational, Structural или Behavioral, а также предоставляет краткое описание назначения этой категории.
Вы организуете код в трёх файлах:
PatternCategory.h: определите абстрактный базовый класс под названиемPatternCategory, который представляет категорию паттернов проектирования. В нём должны быть:- Чистый виртуальный method
getName(), возвращающий название категории в виде строки - Чистый виртуальный method
getPurpose(), возвращающий описание того, что делают паттерны в этой категории - Виртуальный деструктор
Затем создайте три производных класса, наследующих от
PatternCategory:CreationalCategory: возвращает имя"Creational"и назначение"Object creation mechanisms"StructuralCategory: возвращает имя"Structural"и назначение"Class and object composition"BehavioralCategory: возвращает имя"Behavioral"и назначение"Object interaction and responsibility"
- Чистый виртуальный method
PatternClassifier.h: создайте классPatternClassifier, который может определить, к какой категории относится данный паттерн.В вашем классификаторе должен быть method
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++