Файл: Основы объекно-ориентированного программирования.pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 14.06.2023

Просмотров: 191

Скачиваний: 5

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Одним из важнейших достижений в области ООП является методология паттернов проектирования, иногда называемых шаблонами проектирования [6].

Паттерн — это описание взаимодействия объектов и классов, адаптированных для решения общей задачи проектирования в конкретном контексте. [3] Паттерны выявляются по мере накопления опыта разработок, когда программист использует одну и ту же схему организации и взаимодействия объектов в разных контекстах. Паттерны предназначены, прежде всего, для инкапсуляции изменений[5].

Таким образом, можно сделать вывод, что объектно-ориентированное программирование является естественной эволюцией более ранних нововведений в разработке языков программирования и более модульным и более абстрактным, чем предыдущие попытки абстрагирования данных и переноса деталей программирования на внутренний уровень. Задача, решаемая с использованием методики объектно-ориентированного программирования, описывается в терминах объектов и операций над ними, а программа при таком подходе представляет собой набор объектов и связей между ними. Также необходимо отметить, что современное программирование базируется не только на идеях ООП, но и на применении паттернов проектирования, аккумулирующих наиболее удачные решения типичных проблем, неоднократно возникавших при разработке программного обеспечения.

Глава 2. Основные принципы структурирования

2.1. Инкапсуляция

Абстракция и инкапсуляция дополняют друг друга: абстрагирование направлено на наблюдаемое поведение объекта, а инкапсуляция занимается внутренним устройством. Чаще всего инкапсуляция выполняется посредством скрытия информации, то есть маскировкой всех внутренних деталей, не влияющих на внешнее поведение. Обычно скрываются и внутренняя структура объекта, и реализация его методов [7].

Непосредственно в описании объекта имеются только заголовки подпрограмм, а тело каждой подпрограммы задается отдельно. Описания полей всегда должны предшествовать заголовкам.

После того, как объектный тип объявлен, можно создавать переменные этого типа, или экземпляры объекта [3].

После того как экземпляр объекта создан, его поля становятся доступными для методов.

Иначе говоря, инкапсуляция – это объединение записей с процедурами и функциями, что превращает их в новый тип данных – объект [7].


То есть инкапсуляция представляет собой способности языка скрывать излишние детали реализации от пользователя объекта. Например, предположим, что используется класс по имени DatabaseReader, который имеет два главных метода: Open() и Close().

Фиктивный класс DatabaseReader инкапсулирует внутренние детали нахождения, загрузки, манипуляций и закрытия файла данных. Одним из основных особенностей данного метода является то, что он позволяет значительно сократить кодирование программы. Так как, нет необходимости прописывать дополнительно метод для реализации функционирования класса DatabaseReader, а требуется просто создать экземпляр и отправлять ему соответствующие сообщения [5].

DatabaseReader reader = new DatabaseReader.Builder("/path/to/GeoIP2-City.mmdb").build();

С идеей инкапсуляции программной логики тесно связана идея защиты данных. В идеале данные состояния объекта должны быть специфицированы с использованием ключевого слова private (или, возможно, protected). Таким образом, это позволяет защитить от несанкционированного доступа к объекту и от изменения или получение лежащего в основе значения. Это неплохой принцип, поскольку общедоступные элементы данных можно легко не преднамеренно повредить[5].

Основной единицей инкапсуляции в C# является класс, который определяет форму объекта. Он описывает данные, а также код, который будет ими оперировать. В C# описание класса служит для построения объектов, которые являются экземплярами класса. Следовательно, класс, по существу, представляет собой ряд схематических описаний способа построения объекта [4].

Код и данные, составляющие вместе класс, называют членами. Данные, определяемые классом, называют полями, или переменными экземпляра. А код, оперирующий данными, содержится в функциях-членах, самым типичным представителем которых является метод. [3] В C# метод служит в качестве аналога подпрограммы. К числу других функций-членов в свою очередь относятся свойства, события и конструкторы. Следовательно, методы класса содержат код, воздействующий на поля, определяемые этим классом.

Следовательно, инкапсуляция представляет собой объединение данных и обрабатывающих их методов (подпрограмм) внутри класса (объекта). Это означает, что в классе объединяются и помещаются внутрь поля, свойства и методы. При этом класс получает определенную функциональность, например, обеспечивая полный набор средств, для создания программы поддержки некоторого элемента интерфейса (окна Windows, редактора и т. п.) или прикладной обработки.


2.2. Наследование

Наследование — это процесс порождения новых объектов-потомков от существующих объектов-родителей, при этом потомок наследует от родителя все его поля, свойства и методы. В дальнейшем наследуемые поля, свойства и методы можно использовать в неизменном виде или переопределять (модифицировать)[7].

Просто наследование большого смысла не имеет, поэтому в объект-потомок добавляются новые элементы, определяющие его особенность и функциональность. Удалить какие-либо элементы родителя в потомке нельзя. В свою очередь, от нового объекта можно породить следующий объект, в результате образуется дерево объектов (называемое также иерархией классов).

Наследование – это использование объекта для построения иерархии порожденных объектов с наследованием доступа каждого из порожденных объектов к коду предка.

Существует тип, служащий основой для создания нового объекта, называемый предком или родительским типом, а создаваемый объект – потомком или дочерним типом [8]. Благодаря наследованию на основе существующего объекта можно создать любое количество новых объектов.

В качестве примера рассмотрим следующую иерархическую зависимость, которая представлена в приложении 1, где показана структура программы, описывающая характеристики машины.

Класс «MySportCar» - это общая часть класса «MyCar», в свою очередь «MyCar» является частью еще более общего класса объектов «Program». Каждый раз порожденный класс наследует все, связанное с родителем, и добавляет к ним свои собственные определяющие характеристики.

То есть наследование представляет собой процесс, в ходе которого один объект приобретает свойства другого объекта. Это очень важный процесс, поскольку он обеспечивает принцип иерархической классификации.[2]

Если не пользоваться иерархиями, то для каждого объекта необходимо явно определять все его свойства. А если воспользоваться наследованием, то достаточно определить, лишь определенные характеристики, которые делают объект особенным в его классе. Он может также наследовать общие свойства своего родителя. Следовательно, благодаря механизму наследования один объект становится отдельным экземпляром более общего класса [3].

Немало важную роль в наследовании играют модификаторы доступа, которые позволяют организовать иерархию объектов.

Используя public-наследование, потомкам передаётся всё, что есть в основном классе, в таком виде, как и записано в основном классе. В итоге образуется дубликат основного класса. Разница в том, что элементы основного класса к элементам данного дубликата отношения не имеют.


Используя private-наследование, можно создать первого потомка, от которого дальнейшее наследование будет бессмысленно. Если первый потомок получает возможность работы с некоторыми элементами, переданными по механизму наследования, то потомки первого потомка таких возможностей не получают. Кроме того, потомки первого потомка даже лишены возможности узнавать, кто их первый родитель[1].

Использованием protected-наследования программистом предполагается, что внутри всех потомков будут использоваться только такие элементы, передаваемые механизмом наследования, которые будут защищены от влияния на себя извне своих классов[3].

Таким образом, процесс, с помощью которого один тип наследует характеристики другого типа, называется наследованием. Наследование объектов аналогично общепризнанному понятию наследования, когда определяется новый объект, как потомок уже существующего объекта, то утверждается, что потомок по большей части такой же, как и предок. К объекту-потомку в случае необходимости могут быть объявлены новые поля, новые методы и перекрыты уже существующие методы предка. Эти добавления и изменения определяют только то, в чем потомок отличается от предка.

2.3. Полиморфизм

Полиморфизм — присваивание действию одного имени, которое затем совместно используется вниз и вверх по иерархии объектов, причем каждый объект иерархии выполняет это действие способом, именно ему подходящим [9]. «Полиморфизм» представляет собой способность обладать несколькими формами, отмечается автором [1]. В объектно-ориентированной разработке это относится к сущностям (элементам структур данных), способным в процессе выполнения присоединяться к объектам разных типов.

Полиморфизм дает возможность применения одних и тех же функций для решения различных задач и находит свое отражение в том, что под одним именем содержатся разные действия, наполнение которых зависит от типа объекта. Производные одного базового класса считаются полиморфными. Это подразумевает, что им присущи как общие характеристики, так и собственные свойства. Касательно средств, которые связаны с возможностью реализации полиморфизма, то следует упомянуть следующие виды методов в ООП[3].

Во-первых, это статические методы класса включаются в код программы в процессе ее компиляции. Таким образом, до запуска программы уже известно, какая процедура будет вызвана в определенной точке, происходит так называемое раннее связывание (Early binding). То есть ситуация, при которой адрес вызываемого метода известен уже в момент компоновки[4].


Во-вторых, это виртуальные методы, которые подключаются к основному коду на этапе выполнения программы и дают возможность определить тип и конкретизировать экземпляр объекта в процессе исполнения, а затем вызвать методы этого объекта. Данный механизм именуется также поздним связыванием (Late binding). Это ситуация, при которой адрес вызываемого метода неизвестен до момента выполнения программы. Адресация разрешается путем использования таблиц виртуальных методов с адресами методов.

Реализация позднего связывания в языке программирования позволяет создавать переменные − указатели на объекты, принадлежащие различным классам (полиморфные объекты), что существенно расширяет возможности языка.

Термины «раннее связывание» и «позднее» относятся к этапу, на котором обращение к процедуре связывается с ее адресом. В случае раннего связывания адреса всех функций и процедур известны в тот момент, когда происходят компиляция и компоновка программы. Это позволяет приписать каждому обращению к процедуре соответствующий адрес. В большинстве традиционных языков, включая С и Паскаль, используется только раннее связывание.[8] В противоположность этому, в случае позднего связывания адрес процедуры не связывается с обращением к ней до этого момента, пока обращение не произойдет фактически, т.е. во время выполнения программы.

Полиморфизм – задание одного имени действию, которое передается вверх и вниз по иерархии объектов с реализацией этого действия способом, соответствующим каждому объекту в иерархии [7].

Рассмотрим для примера стек, т.е. область памяти, функционирующую по принципу «последним пришел — первым обслужен». Допустим, что в программе требуются три разных типа стеков: один — для целых значений, другой — для значений с плавающей точкой, третий — для символьных значений. В данном примере алгоритм, реализующий все эти стеки, остается неизменным, несмотря на то, что в них сохраняются разнотипные данные. В языке, не являющемся объектно-ориентированным, для этой цели пришлось бы создать три разных набора стековых подпрограмм с разными именами. Но благодаря полиморфизму для реализации всех трех типов стеков в C# достаточно создать лишь один общий набор подпрограмм [4]. Зная, как пользоваться одним стеком, вы сумеете воспользоваться и остальными.

В более общем смысле понятие полиморфизма нередко выражается следующим образом: «один интерфейс — множество методов». Это означает, что для группы взаимосвязанных действий можно разработать общий интерфейс. Полиморфизм помогает упростить программу, позволяя использовать один и тот же интерфейс для описания общего класса действий. Выбрать конкретное действие (т.е. метод) в каждом отдельном случае — это задача компилятора. Программисту не нужно делать это самому. Ему достаточно запомнить и правильно использовать общий интерфейс[5].