Научная Петербургская Академия

Курсовая: Объектно-ориентированное программирование

Курсовая: Объектно-ориентированное программирование

1. Введение

Концепция объектно-ориентированного программирования подразумевает, что

основой управления процессом реализации программы является передача сообщений

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

которые они должны реагировать при выполнении программы. В этом состоит главное

отличие ООП от процедурного программирования, где отдельно определённые

структуры данных передаются в процедуры (функции) в качестве параметров. Таким

образом, объектно-ориентированная программа состоит из объектов – отдельных

фрагментов кода, обрабатывающего данные, которые взаимодействуют друг с другом

через определённые интерфейсы.

Объектно-ориентированный язык программирования должен обладать следующими

свойствами:

1. абстракции – формальное о качествах или свойствах предмета

путем мысленного удаления некоторых частностей или материальных объектов;

2. инкапсуляции – механизма, связывающего вмести код и данные,

которыми он манипулирует, и защищающего их от внешних помех и некорректного

использования;

3. наследования – процесса, с помощью которого один объект

приобретает свойства другого, т.е. поддерживается иерархической классификации;

4. полиморфизма – свойства, позволяющего использовать один и тот

же интерфейс для общего класса действий.

Разработка объектно-ориентированных программ состоит из следующих

последовательных работ:

- определение основных объектов, необходимых для решения данной задачи;

- определение закрытых данных (данных состояния) для выбранных объектов;

- определение второстепенных объектов и их закрытых данных;

- определение иерархической системы классов, представляющих выбранные

объекты;

- определение ключевых сообщений, которые должны обрабатывать объекты

каждого класса;

- разработка последовательности выражений, которые позволяют решить

поставленную задачу;

- разработка методов, обрабатывающих каждое сообщение;

- очистка проекта, то есть устранение всех вспомогательных

промежуточных материалов, использовавшихся при проектировании;

- кодирование, отладка, компоновка и тестирование.

Объектно-ориентированное программирование позволяет программисту моделировать

объекты определённой предметной области путем программирования их содержания

и поведения в пределах класса. Конструкция «класс» обеспечивает механизм

инкапсуляции для реализации абстрактных типов данных. Инкапсуляция как бы

скрывает и подробности внутренней реализации типов, и внешние операции и

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

2. Что такое объектно-ориентированное программирование

Элементы объектно-ориентированного программирования (ООП) появились в начале

70-х годов в языке моделирования Симула, затем получили свое развитие, и в

настоящее время ООП принадлежит к числу ведущих технологий программирования.

Основная цель ООП, как и большинства других подходов к программированию –

повышение эффективности разработки программ. Идеи ООП оказались плодотворными

и нашли применение не только в языках программирования, но и в других

областях Computer Science, например, в области разработки операционных

систем.

Появление ООП было связано с тем наблюдением, что компьютерные программы

представляют собой описание действий, выполняемых над различными

объектами. В роли последних могут выступать, например, графические объекты,

записи в базах данных или совокупности числовых значений. В традиционных

методах программирования изменение данных или правил и методов обработки часто

приводило к необходимости значительного изменения программы. Всякое

существенное изменения программы – это большая неприятность для программиста,

так как при этом увеличивается вероятность ошибок, вследствие чего возрастает

время, необходимое для «доводки» программы. Использование ООП позволяет выйти

из такой ситуации с минимальными потерями, сводя необходимую модификацию

программы к её расширению и дополнению. Необходимо заметить, что ООП не

является панацеей от всех программистских бед, но его ценность как передовой

технологии программирования несомненна. Изучение идей и методов ООП может

существенно упростить разработку и отладку сложных программ.

Мы уже привыкли использовать в своих программах процедуры и функции для

программирования тех сложных действий по обработке данных, которые приходится

выполнять многократно. Использование подпрограмм в своё время было важным

шагом на пути к увеличению эффективности программирования. Подпрограмма может

иметь формальные предметы, которые при обращении к ней заменяются

фактическими предметами. В этом случае есть опасность вызова подпрограммы с

неправильными данными, что может привести к сбою программы и её аварийному

завершению при выполнении. Поэтому естественным обобщением традиционного

подхода к программированию является объединение данных и подпрограмм

(процедур и функций), предназначенных для их обработки.

3. Объекты

Базовым в объектно-ориентированном программировании является понятие

объекта. Объект имеет определённые свойства. Состояние объекта задаётся

значениями его признаков. Объект «знает», как решать определённые задачи, то

есть располагает методами решения. Программа, написанная с использованием ООП,

состоит из объектов, которые могут взаимодействовать между собой.

Ранее отмечалось, что программная реализация объекта представляет собой

объединение данных и процедур их обработки. Переменные объектного типа называют

экземплярами объекта. Здесь требуется уточнение – экземпляр можно лишь

формально назвать переменной. Его описание даётся в предложение описания

переменных, но в действительности экземпляр – нечто большее, чем обычная

переменная.

В отличие от типа «запись», объектный тип содержит не только поля, описывающие

данные, но также процедуры и функции, описания которых содержится в описании

объекта. Эти процедуры и функции называют методами. Методам объекта

доступны его поля. Следует отметить, что методы и их параметры определяются в

описании объекта, а их реализация даётся вне этого описания, в том мест

программы, которое предшествует вызову данного метода. В описании объекта

фактически содержаться лишь шаблоны обращения к методам, которые

необходимы компилятору для проверки соответствия количества параметров и их

типов при обращении к методам. Вот пример описания объекта

[1]:

Type

Location = object

X,Y: Integer;

Procedure Init(InitX, InitY: Integer);

Function GetX: Integer;

Function GetY: Integer;

End;

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

в графическом режиме и который предназначен для определения положения на

экране произвольного графического элемента. Объект описывается с помощью

зарезервированных слов

object.end, между которыми находиться описание полей и методов. В нашем примере

объект содержит два поля для хранения значений графических координат, а так же

для описания процедуры и двух функций - это методы данного объекта.

Процедура предназначена для задания первоначального положения объекта, а

функция – для считывания его координат.

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

Инкапсуляция является важнейшим свойством объектов, на котором строится

объектно-ориентированное программирование. Инкапсуляция заключается в том, что

объект скрывает в себе детали, которые несущественны для использования объекта.

В традиционном подходе к программированию с использованием глобальных

переменных программист не был застрахован от ошибок, связанных с использованием

процедур, не предназначенных для обработки данных, связанных с этими

переменными. Предположим, например, что имеется «не-ООП» программа,

предназначенная для начисления заработной платы сотрудникам некой организации,

а в программе имеются два массива. Один массив хранит величину заработной

платы, а другой – телефонные номера сотрудников (для составления отчёта для

налоговой инспекции). Что произойдёт, если программист случайно перепутает эти

массивы? Очевидно, для бухгалтерии начнутся тяжёлые времена. «Жёсткое»

связание данных и процедур их обработки в одном объекте позволит избежать

неприятностей такого рода. Инкапсуляция и является средством организации

доступа к данным только через соответствующие методы.

В нашем примере описание объекта процедура инициализации Init и функции GetX

и GetY уже не существуют как отдельные самостоятельные объекты. Это

неотъемлемые части объектного типа Location. Если в программе имеется

описание нескольких переменных указанного типа, то для каждой переменной

резервируется своя собственная область памяти для хранения данных, а

указатели на точки входа в процедуру и функции – общие. Вызов каждого метода

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

каких данных предназначен данный метод.

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

Наследование – это ещё одно базовое понятие объектно-ориентированного

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

свойства прежних, дополняя или изменяя их. Объект-наследник получает все поля и

методы «родителя», к которым он может добавить свои собственные поля и методы

или заменить («перекрыть») их своими методами. Пример описания

объекта-наследника даётся ниже:

Tipe

Point = object(Location)

Visible: Boolean;

Procedure Int(IntX, IntY: Integer);

Procedure Show;

Procedure Hide;

Function IsVisible: Boolean;

Procedure MoveTo(NewX, NewY: Integer);

End;

Наследником здесь является объект Point, описывающий графическую точку, а

родителем – объект Location. Наследник не содержит описание полей и методов

родителя. Имя последнего указывается в круглых скобках после слова object. Из

методов наследника можно вызывать методы родителя. Для создания наследника не

требуется иметь исходный текст объекта родителя. Объект-родитель может быть

уже в составе оттранслированного модуля.

В чём привлекательность наследования? Если некий объект был уже определён и

отлажен, он может быть использован и в других программах. При этом может

оказаться, что новая задача отличается от предыдущей, и возникает

необходимость некоторой модификации как данных, так и методов их обработки.

Программисту приходится решать дилемму – создания объектов заново или

использовать результаты предыдущей работы, применяя механизм наследования.

Первый путь менее эффективен, так как требует дополнительных затрат времени

на отладку и тестирование. Во втором случае часть этой работы оказывается

выполненной, что сокращает время на разработку новой программы. Программист

при этом может и не знать деталей реализации объекта-родителя.

В нашем примере к объекту, связанному с определением положения графического

элемента, просто добавилось новое поле, описывающее признак видимости

графической точки, и несколько новых методов, связанных с режимом отображения

точки и её преобразованиями.

6. Виртуальные методы

Наследование позволяет создавать иерархические, связанные отношениями

подчинения, структуры данных. Следует, однако, заметить, что при

использовании этой возможности могут возникнуть проблемы. Предположим, что в

нашей графической программе необходимо определить объект Circle, который

является потомком другого объекта Point:

Type

Circle = object (point)

Radius: Integer;

Procedure Show;

Procedure Hide;

Procedure Expand(ExpandBy: Integer);

Procedure Contact(ContactBy: Integer);

End;

Новый объект Circle соответствует окружности. Поскольку свойства окружности

отличаются от свойств точки, в объекте-наследнике придется изменять процедуры

Show и Hide, которые отображают окружность и удаляют её изображение с экрана.

Может оказаться, что метод Init (см. предыдущий пример) объекта Circle,

унаследованный от объекта Point, также использует методы Show и Hide, впредь

во время трансляции объекта Point использует ссылки на старые методы.

Очевидно в объекте Circle они работать не будут. Можно, конечно, попытаться

«перекрыть» метод Init. Чтобы это сделать, нам придётся полностью

воспроизвести текст метода. Это усложни работу, да и не всегда возможно,

поскольку исходного текста программы может не оказаться под рукой (если

объект-родитель уже находиться в оттранслированном модуле).

Для решения этой проблемы используется виртуальный метод. Связь между

виртуальным методом и вызывающими их процедурами устанавливается не во время

трансляции (это называется ранним связанием), а во время выполнения

программы (позднее связание.

Чтобы использовать виртуальный метод, необходимо в описании объекта после

заголовка метода добавить ключевое слово virtual. Заголовки виртуальных методов

родителя и наследника должны в точности совпадать. Инициализация экземпляра

объекта, имеющего виртуальные методы, должна выполняться с помощью специального

метода – конструктора. Конструктор обычно присваивает полям объекта

начальные значения и выполняет другие действия по инициализации объекта. В

заголовке метода-конструктора слово procedure заменяется словом constructor.

Действия обратные действиям конструктора, выполняет ещё один специальный метод

деструктор. Он описывается словом destructor.

Конструктор выполняет действия по подготовке позднего связывания. Эти действия

заключаются в создании указателя на таблицу виртуальных методов,

которая в дальнейшем используется для поиска методов. Таблица содержит адреса

всех виртуальных методов. При вызове виртуального метода по его имени

определяется адрес, а затем по этому адресу передается управление.

У каждого объектного типа имеется своя собственная таблица виртуальных

методов, что позволяет одному и тому же оператору вызывать разные процедуры.

Если имеется несколько экземпляров объектов одного типа, то недостаточно

вызвать конструктор для одного из них, а затем просто скопировать этот

экземпляр во все остальные. Каждый объект должен иметь свой собственный

конструктор, который вызывается для каждого экземпляра. В противном случае

возможен сбой в работе программы.

Заметим, что конструктор или деструктор, могут быть «пустыми», то есть не

содержать операторов. Весь необходимый код в этом случае создается при

трансляции ключевых слов construct и destruct.

7. Динамическое создание объектов

Переменные объектного типа могут быть динамическими, то есть размещаться

в памяти только во время их использования. Для работы с динамическими объектами

используются расширенный синтаксис процедур New и Dispose. Обе процедуры в этом

случае содержат в качестве второго параметра вызов конструктора или деструктора

для выделения или освобождения памяти переменной объектного типа:

New(P, Construct)

или

Dispose(P, Destruct)

Где P – указатель на переменную объектного типа, а Construct или Destruct –

конструктор и деструктор этого типа.

Действие процедуры New в случае расширенного синтаксиса равносильно действию

следующей пары операторов:

New(P);

P^.Construct;

Эквивалентом Dispose является следующее:

P^Dispose;

Dispose(P)

Применение расширенного синтаксиса не только улучшает читаемость исходного

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

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

Полиморфизм заключается в том, что одно и то же имя может соответствовать

различным действиям в зависимости от типа объекта. В тех примерах, которые

рассматривались ранее, полиморфизм проявлялся в том, что метод Init действовал

по-разному в зависимости от того, является объект точкой или окружностью.

Полиморфизм напрямую связан с механизмом позднего связывания. Решение о том,

какая операция должна быть выполнена в конкретной ситуации, принимается во

время выполнения программы.

Следующий вопрос, связанный с использованием объектов, заключается в

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

свойства совместимости с другими объектами своего родителя. В правой части

оператора присваивания вместо типов родителя можно использовать типы

наследника, но не наоборот. Таким образом, в нашем примере допустимы

присваивания:

Var

Alocation : Location;

Apoin : Point;

Acircle : Circle;

Alocation :=Apoint

Apoint := Acrcle;

Alocation := Acircle;

Дело в том, что наследник может быть более сложным объектом, содержащим поля

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

экземпляру объекта-наследника может оставить некоторые поля неопределёнными

и, следовательно, представляет потенциальную опасность. При выполнении

оператора присвоения копируются только те поля данных, которые являются

общими для обоих типов.

[1] Выполняется на языке Turbo Pascal,

начиная с версии 5.0. Далее все примеры даны для выполнения на этом языке

программирования.



(C) 2009