Объектно-ориентированное проектирование. Основа для проектирования классов
Приступил к изучению объектно-ориентированного проектирования и первая тема посвящена проектированию классов.
Введем понятие абстрактного типа данных (АТД). Слово “абстрактного” здесь говорит об отсутствии конкретной реализации при рассуждении о типе данных. Все мы знаем типы данных, которые могут быть базовыми и пользовательскими. Так вот, абстрактный тип данных описывает интерфейс работы с типом данных, без конкретной реализации. Например, АТД “Stack”. Мы можем описать работу стека, операции над ним, но ничего не говорим про реализацию, а она может быть разной. Например, на основе массива или на основе связного списка.
Теперь формальное определение из Вики: Абстра́ктный тип да́нных (АТД) — это математическая модель для типов данных, где тип данных определяется поведением (семантикой) с точки зрения пользователя данных, а именно в терминах возможных значений, возможных операций над данными этого типа и поведения этих операций. Формально АТД может быть определён как множество объектов, определяемое списком компонентов (операций, применимых к этим объектам, и их свойств). Вся внутренняя структура такого типа спрятана от разработчика программного обеспечения — в этом и заключается суть абстракции. Абстрактный тип данных определяет набор функций, независимых от конкретной реализации типа, для оперирования его значениями. Конкретные реализации АТД называются структурами данных.
В программировании абстрактные типы данных обычно представляются в виде интерфейсов, которые скрывают соответствующие реализации типов. Программисты работают с абстрактными типами данных исключительно через их интерфейсы, поскольку реализация может в будущем измениться. Такой подход соответствует принципу инкапсуляции в объектно-ориентированном программировании. Сильной стороной этой методики является именно сокрытие реализации. Раз вовне опубликован только интерфейс, то пока структура данных поддерживает этот интерфейс, все программы, работающие с заданной структурой абстрактным типом данных, будут продолжать работать. Разработчики структур данных стараются, не меняя внешнего интерфейса и семантики функций, постепенно дорабатывать реализации, улучшая алгоритмы по скорости, надёжности и используемой памяти.
Общая схема построения объектно-ориентированной программы Включает в себя следующие положения:
- Всю систему типов в проекте строим на классах;
- Строим систему как набор равноправных классов. Все общение между классами только посредством вызовов методов классов (также известное как “отправка сообщения”) Используем generics
- Отвязываемся от конкретных реализаций класса, работаем с интерфесом типа (пример, List вместо ArrayList)
Для добавления АТД в проект мы сперва определим его тип (возможно, дженерик), затем опишем интерфейс типа (методы, через которые будем посылать сообщения типу). Дальше определим условия, которые будут накладывать ограничения на метод. Это пред- и пост- условия. Так, на примере со стеком, предусловие для удаления элемента будет наличие в стеке хотя бы одного элемента (стек не должен быть пуст). А постусловие для добавления элемента будет, собственно, успешность операции добавления. То есть элемент помещен в стек.
Интересный момент, для упрощения проектирования АТД мы можем выделить 3 категории методов классов, которые реализуют абстрактный тип данных, а именно:
- Конструкторы
- Запросы. Это методы, которые вычисляют некоторое значение, но не меняют состояние класса. Это так называемые чистые функции и для них требуются предусловия
- Команды. Это методы, меняющие состояние полей класса. Для них требуются постусловия
Рассмотрим работу методов как команд. Вообще, команды никакого значения не возвращают, но бывает необходимо узнать результат их работы. Правильный подход заключается в том, чтобы делать дополнительный запрос на получение статуса результата последней работы команды. Здесь задача заключается в правильном выборе возможных статусов команд, и, конечно, стоит учесть, что вызов статуса команды может быть вызван до того, как команда отработала хоть раз.
Итак, некоторые выводы:
Абстрактный тип данных представляет собой интерфейс для работы с типом данных, определяющий его операции и свойства, независимо от конкретной реализации.
АТД описывает только “что” может быть сделано с данными, не указывая на “как” это делается. Реализацию можно выбирать самостоятельно, используя различные структуры данных. Например, для реализации стека можно использовать массив или связный список.
АТД являются основой для разработки алгоритмов и структур данных, позволяют абстрагироваться от деталей реализации и сосредоточиться на работе с данными.
АТД может быть определен как множество объектов, описываемое операциями, применимыми к этим объектам, и их свойствами.
В программировании АТД обычно представляются в виде интерфейсов, которые скрывают конкретные реализации типов данных. Работа с АТД осуществляется только через их интерфейсы, что обеспечивает гибкость и удобство при изменении реализации.
Для добавления АТД в проект необходимо определить тип данных (возможно, дженерик), описать интерфейс с методами, наложить ограничения на множество значений, с которыми работает метод (предусловия и/или постусловия).
Методы классов, реализующие АТД, можно разделить на конструкторы, запросы (чистые функции) и команды, изменяющие состояние класса. Если требуется получать результат работы команды, то правильный объектно-ориентированный подход предполагает явно вызывать статус отработавшей команды. Следует учитывать различные статусы, и то, что команда может еще ни разу не отработать.
Абстрактные типы данных позволяют отвязаться от конкретных реализаций классов, работать с интерфейсами типов и использовать принцип инкапсуляции в объектно-ориентированном программировании.
Интервью с Барбарой Лисков: https://www.quantamagazine.org/barbara-liskov-is-the-architect-of-modern-algorithms-20191120/