Основные понятия теории ООП Абстракция Абстракция в ООП — это использование только тех характеристик объекта, которые с достаточной точностью представляют его в данной системе. Основная идея состоит в том, чтобы представить объект минимальным набором полей и методов и при этом с достаточной точностью для решаемой задачи. Абстракция является основой объектно-ориентированного программирования и позволяет работать с объектами, не вдаваясь в особенности их реализации. Абстракция данных — одно из наиболее старых понятий объектно-ориентированного программирования, возникшее ещё до его появления. Абстракция данных связывает лежащий в основе тип данных с набором операций над ним (АТД). Пользователь типа данных не имеет прямого доступа к его реализации, но может работать с данными через предоставленный набор операций. Преимущество абстракции данных в разделении операций над данными и внутреннего представления этих данных, что позволяет изменять реализацию, не затрагивая пользователей типа данных. Такое разделение может быть выражено через специальный «интерфейс», который сосредотачивает описание всех возможных применений программы. С точки зрения теории множеств, процесс представляет собой организацию для группы подмножеств своего множества. АТД Абстрактный тип данных (АТД) — это математическая модель для типов данных, где тип данных определяется поведением (семантикой) с точки зрения пользователя данных, а именно в терминах возможных значений, возможных операций над данными этого типа и поведения этих операций. Формально АТД может быть определён как множество объектов, определяемое списком компонентов (операций, применимых к этим объектам, и их свойств). Вся внутренняя структура такого типа спрятана от разработчика программного обеспечения — в этом и заключается суть абстракции. Абстрактный тип данных определяет набор функций, независимых от конкретной реализации типа, для оперирования его значениями. Конкретные реализации АТД называются структурами данных. В программировании абстрактные типы данных обычно представляются в виде интерфейсов, которые скрывают соответствующие реализации типов. Программисты работают с абстрактными типами данных исключительно через их интерфейсы, поскольку реализация может в будущем измениться. Такой подход соответствует принципу инкапсуляции в объектно-ориентированном программировании. Сильной стороной этой методики является именно сокрытие реализации. Раз вовне опубликован только интерфейс, то пока структура данных поддерживает этот интерфейс, все программы, работающие с заданной структурой абстрактным типом данных, будут продолжать работать. Разработчики структур данных стараются, не меняя внешнего интерфейса и семантики функций, постепенно дорабатывать реализации, улучшая алгоритмы по скорости, надёжности и используемой памяти. Различие между абстрактными типами данных и структурами данных, которые реализуют абстрактные типы, можно пояснить на следующем примере. Абстрактный тип данных «список» может быть реализован при помощи массива или линейного списка с использованием различных методов динамического выделения памяти. Однако каждая реализация определяет один и тот же набор функций, который должен работать одинаково (по результату, а не по скорости) для всех реализаций. Абстрактные типы данных позволяют достичь модульности и иметь несколько альтернативных взаимозаменяемых реализаций отдельного модуля. Классы Класс - это абстрактный тип данных, поставляемый с возможно частичной реализацией. Абстрактные типы данных (АТД) являются математическим понятием, пригодным на этапе подготовки спецификации - в процессе анализа. Понятие класса, обеспечивает необходимую связь с разработкой ПО на этапах проектирования и программирования. Эффективный класс - если его реализация полна. Отложенный класс - частичная реализации класса. Аналогично АТД, класс - это тип, описывающий множество возможных структур данных, называемых экземплярами (instances) класса. Экземпляры АТД являются абстракциями – элементами математического множества. Экземпляр класса конкретен – это структура данных, размещаемая в памяти компьютера и обрабатываемая программой. Пример: Если определить класс STACK и взять за основу спецификацию АТД из предыдущей лекции, добавить информацию, необходимую для адекватного представления, то экземплярами класса будут структуры данных - конкретные стеки. Пример: Класс POINT, моделирующий точку на плоскости. Если для представления точки выбрана декартова система координат, то каждый экземпляр POINT представляет собой запись с полями x, y - абсциссой точки и ее ординатой. Термин "объект" появляется как побочный продукт определения "класса". Объект это просто экземпляр некоторого класса. Программные тексты, описывающие создаваемую систему, содержат определения классов. Объекты создаются только в процессе выполнения программ. Класс одновременно является модулем и типом. Модули - это структурные единицы, из которых состоит программа. Независимо от конкретного выбора той или иной модульной структуры, модуль всегда рассматривается как синтаксическая концепция. Разбиение на модули влияет лишь на форму записи исходных текстов программ, но не определяет их функциональность. В самом деле, принципиально можно написать программу Ada в виде единственного пакета, или программу Pascal как единую основную программу. Безусловно, такой подход не рекомендуется, и любой компетентный программист будет использовать модульные возможности языка для деления программы на обозримые и управляемые части. Но если взять существующую программу, например на Паскале, то всегда можно собрать воедино все модули и получить работоспособную программу с эквивалентной семантикой. (Присутствие рекурсивных подпрограмм делает этот процесс менее тривиальным, но не оказывает принципиального влияния на данную дискуссию.) Таким образом, деление на модули диктуется принципами управления проектами, а не внутренней необходимостью. Концепция типов на первый взгляд совершенно иная. Тип является статическим описанием вполне определенных динамических объектов - элементов данных, которые обрабатываются во время выполнения программной системы. Набор типов обычно содержит предопределенные типы, такие как INTEGER или CHARACTER, а также пользовательские типы: записи (структуры), указатели, множества (в Pascal), массивы и другие. Понятие типа является семантической концепцией, и каждый тип непосредственно влияет на выполнение программной системы, так как описывает форму объектов, которые система создает и которыми она манипулирует. В не ОО-подходах концепции модуля и типа существуют независимо друг от друга. Наиболее замечательным свойством класса является одновременное использование обеих концепций в рамках единой лингвистической конструкции. Класс является модулем или единицей программной декомпозиции, но одновременно класс это тип (или шаблон типа в тех случаях, когда поддерживается параметризация). Мощь ОО-метода, во многом, следствие этого отождествления. Наследование, в частности, может быть полностью понято только при рассмотрении его, как модульного расширения, так и, одновременно, уточнения специализации типа. Наследование Наследование позволяет описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом. Класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса. Класс, от которого произошло наследование, называется базовым или родительским (англ. base class). Классы, которые произошли от базового, называются потомками, наследниками или производными классами (англ. derived class). Абстрактный класс — это класс, содержащий хотя бы один абстрактный метод, он описан в программе, имеет поля, методы и не может использоваться для непосредственного создания объекта. То есть от абстрактного класса можно только наследовать. Объекты создаются только на основе производных классов, наследованных от абстрактного. Например, абстрактным классом может быть базовый класс «сотрудник вуза», от которого наследуются классы «аспирант», «профессор» и т. д. Так как производные классы имеют общие поля и функции (например, поле «год рождения»), то эти члены класса могут быть описаны в базовом классе. В программе создаются объекты на основе классов «аспирант», «профессор», но нет смысла создавать объект на основе класса «сотрудник вуза». Интерфейс — это чистый абстрактный класс, то есть класс, в котором не определено ничего, кроме абстрактных методов. Плодотворное применение наследования требует переопределения (предоставления классу возможности переписать реализацию некоторых компонентов его собственного предка), полиморфизма (возможности связывать ссылку во время выполнения с экземплярами разных классов), динамического связывания (динамического выбора подходящего варианта переопределенного компонента), совместности типов (требования, чтобы всякая сущность могла присоединяться только к экземплярам типов-наследников). Композиция или наследование? Хорошая статья: https://habr.com/ru/post/325478/?ysclid=l7qgoz61yj835059087 Полиморфизм Полиморфизм — это возможность объектов с одинаковой спецификацией иметь различную реализацию. Язык программирования поддерживает полиморфизм, если классы с одинаковой спецификацией могут иметь различную реализацию — например, реализация класса может быть изменена в процессе наследования. Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество реализаций» (но под это определение подпадает лишь ad-hoc-полиморфизм). Существует несколько разновидностей полиморфизма. Две принципиально различных из них были описаны Кристофером Стрэчи в 1967 году: это параметрический полиморфизм и ad-hoc-полиморфизм, прочие формы являются их подвидами или сочетаниями. Параметрический полиморфизм является истинным, т.к. подразумевает исполнение одного и того же кода для всех допустимых типов аргументов, а ad-hoc-полиморфизм — мнимым, т.к. представляет собой обеспечение косметической однородности потенциально разного исполнимого кода для каждого конкретного типа аргумента]. При этом существуют ситуации, где необходимо использование именно ad-hoc-полиморфизма, а не параметрического. В дальнейшем классификацию уточнил Лука Карделли, выделив четыре разновидности полиморфизма: универсальный параметрический включения (или подтипов) ad-hoc перегрузка приведение типов Полиморфизм позволяет писать более абстрактные программы и повысить коэффициент повторного использования кода. Общие свойства объектов объединяются в систему, которую могут называть по-разному — интерфейс, класс. Полезная статья о полиморфизме: https://medium.com/devschacht/polymorphism-207d9f9cd78 Инкапсуляция Инкапсуляция — процесс разделения элементов абстракций, определяющих ее структуру (данных) и поведение (методов). Инкапсуляция предназначена для изоляции контрактных обязательств абстракции (протокол/интерфейс) от их реализации. На практике это означает, что класс должен состоять из двух частей: интерфейса и реализации. В реализации большинства языков программирования обеспечивается механизм сокрытия, позволяющий разграничивать доступ к различным частям компонента. Однако, сокрытие не является обязательным условием инкапсуляции. В сообществе C++ или Java принято рассматривать инкапсуляцию без сокрытия как неполноценную. Однако, некоторые языки (например, Smalltalk, Python) реализуют инкапсуляцию, но не предусматривают возможности сокрытия в принципе. В общем случае в разных языках программирования термин «инкапсуляция» относится к одной или обеим одновременно следующим нотациям: механизм языка, позволяющий ограничить доступ одних компонентов программы к другим; языковая конструкция, позволяющая связать данные с методами, предназначенными для обработки этих данных. Инкапсуляция неразрывно связана с понятием интерфейса класса. По сути, всё то, что не входит в интерфейс, инкапсулируется в классе.