- •И. А. Андрианов, д. В. Кочкин, с. Ю. Ржеуцкая
- •Учебное пособие
- •Оглавление
- •1. Основы языка 8
- •1.2.2 Простые типы данных 13
- •2. Работа с памятью 73
- •3. Основы объектно-ориентированного программирования 87
- •4.Обработка исключений 114
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов 130
- •6. Паттерны проектирования 159
- •7. Антипаттерны 211
- •9. Методы отладки и оптимизации кода 242
- •1. Основы языка
- •1.1.2 Понятие проекта
- •1.2 Простые типы данных
- •1.2.1 Понятие типа
- •1.2.2 Простые типы данных
- •1.2.3 Внутреннее представление простых типов
- •1.2.4 Ключевое слово typedef. Тип size_t
- •1.3 Константы и переменные
- •1.3.1 Литералы
- •1. Числовые константы:
- •2. Символьные константы:
- •1.3.2 Переменные
- •1.3.3 Описание переменных
- •1.4. Выражения. Преобразование типов
- •1.4.1 Операнды и операции
- •1.4.2 Приоритет операций
- •1.4.3 Преобразование типов
- •1.5 Ветвления и циклы
- •1.5.2 Циклы
- •1.6 Массивы, строки
- •1.6.1 Основные понятия
- •1.6.2 Встроенные массивы
- •1.6.3 Cтроки. Обработка строк с завершающим нулём
- •1.7 Указатели и ссылки. Связь указателей и массивов. Библиотека cstring
- •1.7.1 Понятия указателя и ссылки
- •1.7.2 Связь между массивами и указателями
- •1.7.3 Библиотека cstring
- •1.8 Использование типов vector и string
- •1.8.1 Шаблонный класс vector
- •1.8.2 Класс string
- •1.9 Структуры и объединения. Битовые поля
- •1.10.1 Понятие функции
- •1.10.2 Описание функции и прототип функции
- •1.11 Параметры функции. Способы передачи параметров
- •1.11.1 Параметры функции и глобальные переменные
- •1.11.2 Способы передачи параметров в функцию
- •1.11.3 Передача массивов в функцию
- •1.11.4 Параметры-константы
- •1.11.5 Значения параметров по умолчанию
- •1.12.1 Указатель на функцию
- •1.12.2 Функции с переменным числом параметров
- •1.12.3 Перегрузка функций
- •1.12.4 Встроенные (inline) функции
- •1.13 Рекурсивные функции
- •1.14 Пространства имён
- •1.15 Директивы препроцессора. Макросы
- •2. Работа с памятью
- •2.1 Управление выделением и освобождением памяти
- •2.1.1 Статическое и динамическое выделение памяти
- •2.1.2 Способы динамического выделения и освобождения памяти
- •2.2 Динамические структуры данных
- •2.2.1 Основные понятия
- •2.2.2 Примеры реализации динамических структур на основе указателей
- •3. Основы объектно-ориентированного программирования
- •3.1 Основные понятия ооп
- •3.2.1 Описание класса
- •3.2.2 Область видимости элементов класса. Инкапсуляция
- •3.2.3 Первые примеры
- •3.3. Конструкторы и деструкторы.
- •3.4 Указатель this
- •3.5 Перегрузка операций
- •3.6 Дружественные функции и классы
- •3.7 Статические элементы класса
- •3.8 Наследование и полиморфизм
- •3.8.1. Основные понятия
- •3.8.2 Одиночное наследование
- •3.8.3 Множественное наследование
- •3.8.4 Конструкторы и деструкторы классов-потомков
- •3.9. Полиморфизм при наследовании классов
- •3.9.1 Механизмы раннего и позднего связывания
- •3.9.2 Абстрактные классы
- •4.Обработка исключений
- •4.1 Основные понятия
- •4.2 Перехват исключений
- •4.3 Поиск обработчика исключений. Раскрутка стека.
- •4.4 Повторное возбуждение исключений
- •4.5 "Аппаратные" и "программные" исключения
- •4.6 Стандартные классы исключений
- •4.7 Спецификация исключений, возбуждаемых функцией
- •4.8 Исключения в конструкторах при наследовании
- •4.9. Исключения в деструкторах
- •5. Шаблонные функции и классы. Библиотека стандартных шаблонов
- •5.1 Шаблонные функции
- •5.2 Шаблонные классы
- •5.3 Специализация шаблонов
- •5.4 Шаблонные параметры шаблонов
- •5.5 Разработка шаблонных классов с настраиваемой функциональностью
- •5.6 Использование шаблонов для вычислений на этапе компиляции
- •5.7 Библиотека стандартных шаблонов (stl) – основные понятия
- •5.8 Последовательные контейнеры. Итераторы
- •5.9. Адаптеры контейнеров
- •5.10 Ассоциативные контейнеры
- •5.11 Алгоритмы
- •6. Паттерны проектирования
- •6.1 Порождающие шаблоны
- •6.2 Структурные шаблоны
- •6.3 Шаблоны поведения
- •6.4 Шаблон "фабричный метод" (Factory method)
- •6.5 Шаблон "одиночка" (Singleton)
- •6.6 Шаблон "итератор" (Iterator)
- •6.7 Шаблон "наблюдатель" (Observer)
- •6.8 Шаблон "пул объектов" (Object pool)
- •6.9 Шаблон "команда" (Command)
- •6. 10 Шаблон "посетитель" (Visitor)
- •6.11 Дополнительные задания
- •6.11.1 Шаблон Iterator
- •6.11.2 Шаблон Observer
- •6.11.3 Шаблоны Command и Observer
- •6.11.5 Шаблон Visitor
- •6.11.5 Разработка класса − контейнера
- •6.11.6 Оценка производительности кода
- •7. Антипаттерны
- •7.1 Программирование методом копирования и вставки (Copy-Paste Programming)
- •7.2 Спагетти-код (Spaghetti code)
- •7.3 Магические числа (Magic numbers)
- •7.4 Бездумное комментирование
- •7.5 Жесткое кодирование (Hard code)
- •7.6 Мягкое кодирование (Soft code)
- •7.7 Золотой молоток (Golden hammer)
- •7.8 Слепая вера (Blind faith)
- •7.9 Ненужная сложность (Accidental complexity)
- •7.10 Божественный объект (God Object)
- •7.11 Лодочный якорь (Boat anchor)
- •7.12 Поток лавы (Lava flow)
- •7.13 Изобретение велосипеда (Reinventing the wheel)
- •7.14 Программирование перебором (Programming by permutation)
- •8.1 Выведение типов
- •8.2 Списки инициализации
- •8.3 Улучшение процесса инициализации объектов
- •8.4 Цикл for по коллекции
- •8.5 Лямбда-функции
- •8.6 Константа нулевого указателя nullptr
- •8.7 "Умные" указатели
- •9. Методы отладки и оптимизации кода
- •9.1 Отладка кода
- •9.1.1 Основные этапы отладки
- •9.1.2 Инструменты и приёмы отладки
- •9.2 Оптимизация кода
- •9.2.1 Рекомендации по выполнению оптимизации
- •9.2.2 Методики оптимизации кода
- •Заключение
- •Библиографический список
6.2 Структурные шаблоны
Структурные шаблоны предназначены для решения вопросов построения системы на основе компоновки объектов и классов. Компоновка осуществляется при помощи наследования и композиции. При наследовании структура классов определяется статически, на этапе написания программы. Базовые классы определяют интерфейс для всей иерархии, подклассы определяют детали реализации. При использовании композиции структура классов определяется динамически путем объединения объектов различных классов на этапе выполнения программы.
К структурным шаблонам относятся: адаптер (adapter), мост (bridge), компоновщик (composite), декоратор (decorator), фасад (facade), приспособленец (flyweight), заместитель (proxy).
Шаблон "адаптер" (adapter) предназначен для преобразования интерфейса некоторого класса к ожидаемому виду, позволяющему применить данный класс в программе. Адаптер может быть использован для подключения функциональности сторонних библиотек либо для повторного использования старого кода без его переписывания.
Шаблон "мост" (bridge) позволяет отделить абстракцию (класс, определяющий интерфейс) от реализации. Мост дает возможность использовать несколько реализаций некоторого функционала − например, для разных операционных систем, и переключаться между ними без внесения изменений в программный код.
Шаблон "компоновщик" (composite) предназначен для обобщения способов работы с простыми и сложными (составными) объектами. Обобщение достигается за счет объединения объектов в древовидную структуру и передачи запросов от корневого объекта к подчиненным.
Шаблон "декоратор" (decorator) дает возможность динамически изменять функциональность объектов без необходимости создания новых подклассов, реализующих требуемые функции. Добавление декораторов (дополнительной функциональности) к объекту не требует внесения изменений в программный код.
Шаблон "фасад" (facade) позволяет организовать высокоуровневый интерфейс для множества компонентов системы. Высокоуровневый интерфейс позволяет упростить выполнение операций, затрагивающих большое количество компонентов системы.
Шаблон "приспособленец" (flyweight) позволяет применить объектно-ориентированный подход для управления множеством мелких сущностей, например, символов в строке текстового редактора. Так как символов в документе может быть много, создание отдельного объекта для каждого из них приведет к неоправданно высокому расходу памяти. Данный шаблон позволяет выделить внутреннее и внешнее состояние объекта, за счет чего уменьшается расход памяти и достигается удобство объектно-ориентированного подхода.
Шаблон "заместитель" (proxy) позволяет использовать вместо некоторого объекта его заменитель и при необходимости создать сам объект. Например, в целях оптимизации можно реализовать отложенное создание объекта, используя до этого момента его заместитель, который может выполнить часть запросов к объекту без его полной инициализации.
6.3 Шаблоны поведения
Шаблоны поведения определяют распределение обязанностей между объектами классов за счет механизмов делегирования, наследования и композиции.
К шаблонам поведения относятся: цепочка обязанностей (chain of responsibility), команда (command), итератор (iterator), интерпретатор (interpretator), посредник (mediator), хранитель (memento), наблюдатель (observer), состояние (state), стратегия (strategy), шаблонный метод (template method), посетитель (visitor).
Шаблон "цепочка обязанностей" (chain of responsibility) представляет собой механизм делегирования запроса множеству обработчиков. Запрос передается последовательно всем обработчикам до тех пор, пока не найдется тот, который его обработает. Данный шаблон позволяет динамически менять обработчики и избегать жесткой связи между запросом и получателем.
Шаблон "команда" (command) инкапсулирует запросы в специальные объекты − команды. Данный шаблон может применяться для систем с фиксированным внутренним состоянием, изменяемым определенными командами. Между командами состояние системы не меняется. Примером такой системы может быть текстовый редактор, а командами − нажатие пользователем на клавиши и ввод символов. Данный шаблон позволяет легко организовать отмену и повторение действий за счет постановки объектов-команд в очередь.
Шаблон "итератор" (iterator) позволяет определить механизм перебора элементов различных коллекций, не раскрывая детали реализации. Итераторы могут быть использованы для создания алгоритмов, не зависящих от типа коллекции элементов, с которыми данные алгоритмы работают. Как правило, итераторы предоставляют следующие операции: получение элемента, на который указывает итератор, переход к следующему элементу, проверка существования следующего элемента.
Шаблон "интерпретатор" (interpreter) позволяет сформулировать решение задачи в виде последовательности команд на некотором языке. Расширение функциональности системы достигается за счет увеличения количества интерпретируемых команд. Наличие программы на интерпретируемом языке позволяет избежать изменения системы под каждую конкретную задачу.
Шаблон "посредник" (mediator) позволяет создать новый составной объект-посредник на основе комбинации существующих объектов. Каждый объект должен иметь информацию только о посреднике, которому он и отправляет сообщения при возникновении различных событий. Объект-посредник, организуя взаимодействие, скрывает связь входящих в его состав объектов.
Шаблон "хранитель" (memento) позволяет сохранить внутреннее состояние объекта за пределами самого объекта для последующего восстановления, при этом хранитель не раскрывает детали реализации объекта. Данный шаблон может применяться совместно с шаблоном "команда" для выполнения отмены операций.
Шаблон "наблюдатель" (observer) позволяет определить связь один-ко-многим между объектами в программе. Такая связь позволяет обеспечить передачу извещений о событиях всем заинтересованным объектам. Например, при изменении текста в редакторе происходит отображение на экране и пересчет статистики. При этом отображение и статистика реализованы в виде отдельных объектов, наблюдающих за текстовым полем редактора. Шаблон "наблюдатель" добавляет системе гибкость за счет динамического изменения связей между объектами и автоматического уведомлении о событиях.
Шаблон "состояние" (state) позволяет динамически менять поведение объекта в зависимости от его состояния. Это становится возможным за счет вынесения логики функционирования в отдельные классы-состояния. Находясь в различных состояниях, объект выполняет одни и те же операции по разному, перенаправляя запросы объекту-состоянию.
Шаблон "стратегия" (strategy) выделяет семейство схожих алгоритмов в отдельную иерархию классов. При этом алгоритмы могут заменяться динамически без перекомпиляции или перезапуска программы. Примером такой иерархии могут быть алгоритмы сохранения изображения в различных графических форматах. Новый алгоритм может быть добавлен путем создания нового класса.
Паттерн "шаблонный метод" (template method) позволяет реализовывать различные версии алгоритма за счет переопределения некоторых операций в подклассах, при этом основа алгоритма определяется в базовом классе. Например, в алгоритме сортировки основные операции будут определены в базовом классе, а в подклассе будет переопределена операция сравнения элементов. Базовый класс будет делегировать подклассу выполнение операции сравнения, вызывая для этого виртуальную функцию.
Шаблон "посетитель" (visitor) позволяет определять операции, применяемые к объектам в коллекции без внесения изменений в сами классы объектов. Класс-коллекция предоставляет механизм передачи посетителя объекту, после чего посетитель выполняет необходимую операцию. Благодаря такому подходу для добавления новой операции необходимо реализовать только новый класс − посетитель.
В следующих разделах представлены некоторые шаблоны проектирования с примерами программного кода.
