Слайд 1Алгоритмизация и программирование
Лекции 30-32
Тема №6
Слайд 2Объектно-ориентированное программирование (object- orient programming, OOP) – это методология программирования,
основанная на представлении программы в виде совокупности объектов, каждый из
которых является экземпляром определенного класса, а классы образуют иерархию наследования.
Слайд 3В данном определении можно выделить три части:
1) ООР использует в качестве
базовых элементов объекты, а не алгоритмы;
2) Каждый объект является экземпляром какого-либо
определенного класса;
3) Классы организованы иерархически.
Программа будет объектно-ориентированной только при соблюдении всех трех требований.
Слайд 4Объект обладает состоянием, поведением и идентичностью;
Структура и поведение схожих
объектов определяет общий для них класс, термины «экземпляр класса» и
«объект» взаимозаменяемы.
Слайд 5Состояние объекта характеризуется перечнем (обычно статическим) всех свойств (атрибутов) данного
объекта и текущими (обычно динамическими) значениями каждого из этих свойств.
Слайд 6Объекты не существуют изолированно, а подвергаются воздействию или сами воздействуют
на другие объекты.
Поведение – это то, как объект действует и
реагирует; поведение выражается в терминах состояния объекта и передачи сообщения. Иными словами, поведение объекта – это его наблюдаемая и проверяемая извне деятельность.
Слайд 7Операцией (сообщением) называется определенное воздействие одного объекта на другой с
целью вызвать соответствующую реакцию.
Операции, выполняемые над данным объектом, называются методами
и входят в описание класса объекта.
Слайд 8Поведение объекта определяется выполняемыми над ним операциями и его состоянием,
причем некоторые операции имеют побочное действие: они изменяют состояние объекта.
Отсюда можно дать другое определение состояния объекта: состояние объекта представляет суммарный результат его поведения.
Слайд 9На практике над объектами совершаются операции пяти видов:
1) Модификатор -
операция, которая изменяет состояние объекта.
2) Селектор- операция, считывающая состояние объекта,
но не меняющая состояние.
3) Итератор- операция, позволяющая организовать доступ ко всем частям объекта в строго определенной последовательности.
4) Конструктор- операция создания и/или его инициализации.
5) Деструктор- операция, освобождающая состояние объекта и/или разрушающая сам объект.
В чистых объектно-ориентированных языках операции могут быть только методами.
Слайд 10Идентичность – это такое свойство объекта, которое отличает его от
всех других объектов.
Класс – это некое множество объектов, имеющих общую
структуру и общее поведение.
Слайд 11Классы и объекты – это отдельные, но тесно связанные понятия.
Каждый объект является экземпляром класса, класс может порождать любое количество
объектов.
Классы статичны, т.е. все их особенности и содержание определены в процессе компиляции программы. Любой объект относится к строго фиксированному классу. Сами объекты, напротив, в процессе выполнения программы создаются и уничтожаются.
Слайд 12Событие –то, что может изменить состояние объекта.
Изменение состояние объекта
это результат использования соответствующего метода объекта (обработчика события).
Слайд 13Отличия в объектной модели в
Object Pascal.
В Object Pascal классами
называются специальные типы, которые содержат поля, методы и свойства. Класс
служит образцом для создания конкретных экземпляров, которые называются объектами.
Слайд 14 Важным отличием классов от других типов является то, что объекты
класса всегда располагаются в динамической памяти (куче), поэтому объект-переменная представляет
собой лишь указатель на динамическую область памяти. Однако при ссылке на содержимое объекта запрещается использовать символ «^» за именем объекта.
Слайд 15В Object Pascal введена новая языковая конструкция — свойства, введены
новые директивы управления областью доступа — published, protected, automated, введены
специальные директивы для динамических (dynamic), перекрываемых (override) и абстрактных (abstract) методов.
Слайд 16В основе объктно-ориентированного программирования лежат три фундаментальных принципа:
инкапсуляция,
наследование,
полиморфизм.
Слайд 17Инкапсуляция
Класс представляет собой единство трех сущностей – полей, методов
и свойств. Объединение этих сущностей в единое целое и называется
инкапсуляцией. Инкапсуляция позволяет во многом изолировать класс от остальных частей программы, сделать его «самодостаточным» для решения конкретной задачи.
Слайд 18Инкапсуляция полезна потому, что помогает перечислить связанные методы и данные
под одной эгидой, а так же скрывать детали реализации, которые
не требуют своей демонстрации или могут быть изменены в будущих версиях объекта.
Слайд 19 Хорошо сконструированные объекты должны состоять из двух частей:
1) Данных и разделов
реализации, скрытых от программистов, использующих объект (с целью защиты данных
от несанкционированных изменений)
2) Набора интерфейсных элементов, предоставляющих возможность программистам обращаться со скрытыми методами и данными.
Слайд 20Для надежной защиты данных и разделов реализации в Delphi определены
директивы объявлений разделов описаний в классе, позволяющие контролировать область видимости
описанных компонентов.
Слайд 21Инкапсуляция представляет собой мощное средство обмена готовыми к работе программными
заготовками. Библиотека классов Delphi – это фактически набор «кирпичиков», созданных
программистами Borland для построения программ.
Слайд 22Наследование.
Любой класс может быть порожден от другого класса. Для
этого при его объявлении указывается имя класса родителя:
TchildClass = class
(TParentClass)
Слайд 23Дочерний класс автоматически наследует поля, методы и свойства своего родителя
и может добавлять их новыми. Таким образом, принцип наследования обеспечивает
поэтапное создание сложных классов и разработку собственных библиотек классов.
Слайд 24Все классы Object Pascal порождены от единственного родителя – класса
Tobject. Этот класс не имеет полей и свойств, но включает
в себя методы самого общего назначения, обеспечивающие весь жизненный цикл любых объектов – от их создания до уничтожения.
Слайд 25Программист не может создать класс, который бы не был дочерним
классом Tobject, т.к. следующие два объявления идентичны:
TMyClass= class (Tobject)
TMyClass= class
Слайд 26В Турбо Паскале для создания объектов используются три зарезервированных слова:
object, constructor, destructor и три стандартные директивы: private, public и
virtual. Зарезервированное слово object используется для описания объекта. Описание объекта должно помещаться в разделе описания типов:
type MyObject = object
{Поля объекта}
{Методы объекта}
end;
Если объект порождается от какого-либо родителя, имя родителя указывается в круглых скобках сразу за словом object:
type MyDescendantObject = object(MyObject)
…
end;
Слайд 27Принцип наследования приводит к созданию ветвящегося дерева классов. Каждый потомок
дополняет возможности своих родителей и передает их своим потомкам.
Слайд 28Полиморфизм.
Полиморфизм – это свойство классов решать схожие по смыслу
проблемы различными способами. В рамках ООП поведение класса определяется набором
входящих в него методов. Изменяя алгоритм того или иного метода в потомках класса, можно придавать этим потомкам отсутствующие у родителя специфические свойства.
Слайд 29Для изменения метода необходимо перекрыть его в потомке, т.е. объявить
в потомке одноименный метод и реализовать в нем нужные действия.
В результате в объекте- родителе и объекте-потомке будут действовать два одноименных метода, имеющих различные алгоритмы.
В ООП полиморфизм достигается также виртуализацией методов, позволяющей родительским методам обращаться к методам своих потомков.
Слайд 30Общую структуру описания класса можно представить в таком виде:
Type
ИмяКласса =
class (ИмяРодит.Класса)
Опубликованные поля;
Опубликованные методы;
Опубликованные свойства;
private
Приватные поля;
Приватные
методы;
Приватные свойства;
Слайд 31public
Общедоступные поля;
Общедоступные методы;
Общедоступные свойства;
protected
Защищенные поля;
Защищенные методы;
Защищенные свойства;
Слайд 32published
Опубликованные поля;
Опубликованные методы;
Опубликованные свойства;
automated
Поля реализации ОLE-механизма;
Методы реализации ОLE-механизма;
Свойства
реализации ОLE-механизма;
end;
Слайд 33Директивы published, protected и automated являются нововведением Object Pascal. Причем
директива automated появилась только в 32-разрядной версии Delphi.
Слайд 34Директива public
Поля, свойства и методы,
описанные в разделе public, называются общедоступными или публичными. Поля, свойства
и методы, расположенные сразу после заголовка класса по умолчанию принимаются общедоступными.
Слайд 35Директива published
Поля, свойства и методы,
описанные в разделе published, называются опубликованными. Их область видимости эквивалентна
области видимости общедоступных описаний. Отличие состоит в том, что для опубликованных полей, свойств и методов генерируется дополнительная информация об их типе, которая доступна во время выполнения.
Слайд 36 Благодаря этой информации при создании и помещении компонент на
палитру, их опубликованные свойства становятся доступными в Object Inspector. Однако
такие свойства могут быть только порядковых типов, вещественных типов, типа String, типа "множество" с максимальным числом элементов не более 15, а также классового типа и типа "указатель на метод".
Слайд 37Директива automated
Поля, свойства и методы, описанные в разделе automated, назовем
по имени директивы автоматическими. Их область видимости эквивалентна области видимости
общедоступных описаний. Отличие состоит в том, что для автоматических свойств и методов генерируется дополнительная информация, которая используется для реализации OLE-механизма.
Слайд 38Директива private
Поля, свойства и методы, описанные в разделе private, называются
приватными или личными. Их область видимости ограничивается пределами того модуля,
в котором они описаны.
Слайд 39Директива protected
Поля, свойства и методы, описанные в разделе protected, называются
защищенными. Директива protected обеспечивает ограничение доступа.
Но если private обеспечивает защиту
на уровне исходного модуля, где сделаны описания, то protected ограничивает доступ на уровне исходного класса.
То есть, если protected-описания принадлежат, например, классу TBaseClass в модуле Uprotec1, то объекты класса TBaseClass, объявленные в "своем" модуле, могут работать с ними, а объекты того же класса, объявленные в других модулях, импортирующих модуль Uprotec1, не могут.
Слайд 40 Полями называются инкапсулированные в класса данные. Поля могут быть любого
типа, в том числе классами. Принято имя поля начинать с
буквы F (Field). Например:
type
TMyClass = class(TForm)
FInt:integer;
FWidth:word;
FPrim1:Tobject;
FFam:string;
end;
Слайд 41Каждый объект получает уникальный набор значений полей, но общий для
всех объектов для данного класса набор методов и свойств. Понятие
инкапсуляции и хороший стиль объектно-ориентированного программирования требуют, чтобы обращение к полям объектов выполнялось исключительно посредством методов. Однако в ОР разрешается обращаться к полям и напрямую. Для этого используются составные имена полей:
Слайд 42Var MyObj1: TmyClass;
…
begin
…
MyObj1.ffam:=’Иванов’;
MyObj1.fwidth:=500;
…
end;
Класс-потомок получает все поля
всех своих предков и может пополнить их своими, но он
не может переопределить их или удалить.
Слайд 43Инкапсулированные в классе процедуры и функции называются методами. Они объявляются,
так же как и обычные подпрограммы:
type
TForm1 = class(TForm)
procedure FormClick(Sender: TObject);
function KeyDown : Word;
end;
Слайд 44Доступ к методам класса осуществляется с помощью составных имен:
Var Form1:
TForm1;
Begin
…
Form1.FormClick(…)
Key:= Form1.KeyDown
…
End;
Слайд 45Методы класса могут перекрываться в потомках. Потомок класса может иметь
сходную по названию процедуру или функцию, которая будет выполнять другое
действие. В ООП возможно статическое и динамическое замещение методов.
Слайд 46Ранним связыванием называется процесс статического связывания методов с объектами во
время компиляции. По умолчанию все методы являются статическими.
Вызов статических
методов выполняется точно также, как и вызовы обычных процедур и функций. Определение конкретных адресов статических методов и их связывание выполняются во время компиляции. Поэтому такие методы не могут быть переопределены для реализации полиморфизма.
Слайд 47Поздним связыванием называется процесс динамического связывания методов с объектами во
время выполнения.
Раннее связывание реализовано для статических методов, а позднее
— для виртуальных, динамических методов и методов обработки сообщений.
Слайд 48Статическое связывание обладает существенным преимуществом над всеми остальными видами адресации,
поскольку обеспечивает самую высокую скорость вызова. Недостатком же фиксированной адресации
является то, что статические методы не подлежат изменениям в классах-потомках. При обращении к статическому методу компилятор точно знает класс, к которому данный метод принадлежит.
Слайд 49Основное различие между виртуальными и динамическими методами состоит в том,
что для их реализации компилятор использует внутренние таблицы различной структуры:
для виртуальных методов — ТВМ (таблицу виртуальных методов), а для динамических методов — ТДМ (таблицу динамических методов).
В ТВМ и ТДМ находятся адреса точек входа динамических и виртуальных методов. При каждом обращении к замещаемому методу компилятор вставляет код, позволяющий извлечь адрес точки входа в подпрограмму из той или иной таблицы.
Динамическое замещение методов
Слайд 50В классе потомке можно переопределить родительский метод с помощью
директивы OVERRIDE.
Получив это указание компилятор создаст код, который на
этапе выполнения программы поместит в родительскую таблицу точку входа виртуального метода класса-потомка, что позволит родителю выполнить нужное действие с помощью нового метода.
Слайд 51Виртуальные методы
Объявление виртуального метода в базовом классе выполняется с помощью
ключевого слова virtual, а его перекрытие в производных классах -
с помощью ключевого слова override.
Перекрытый метод должен иметь точно такой же формат (список параметров, а для функций ещё и тип возвращаемого значения), что и перекрываемый:
Слайд 52type TPeople = class
Name: string;
procedure GetName; virtual; //Виртуальный метод
end;
type TStudent
= class(TPeople)
...
procedure GetName; override;
end;
Слайд 53Суть виртуальных методов в том, что они вызываются по фактическому
типу экземпляра, а не по формальному типу, записанному в программе.
Работа виртуальных методов основана на косвенном вызове подпрограмм. При косвенном вызове команда вызова подпрограммы оперирует не адресом подпрограммы, а адресом места в памяти, где хранится адрес подпрограммы.
Слайд 54Для каждого виртуального метода создаётся процедурная переменная, но её наличие
и использование скрыто от программиста. Все процедурные переменные с адресами
виртуальных методов пронумерованы и хранятся в таблице, называемой таблицей виртуальных методов. Такая таблица создаётся одна для каждого класса объектов, и все объекты этого класса хранят на неё ссылку.
Слайд 55Вызов виртуального метода происходит следующим образом:
1. Через объектную переменную
выполняется обращение к занятому объектом блоку памяти.
2. Далее из
этого блока извлекается адрес таблицы виртуальных методов (он записан в четырёх первых байтах).
3. На основании порядкового номера виртуального метода извлекается адрес соответствующей подпрограммы.
4. Вызывается код, находящийся по этому адресу.
Слайд 56При построении иерархии классов часто возникает ситуация, когда работа виртуального
метода в базовом классе не известна и наполняется содержанием только
в наследниках. Директива abstract записывается после слова virtual и исключает необходимость написания кода виртуального метода для данного класса. Такой метод называется абстрактным. Свою реализацию эти методы получают в законченных наследниках.
Слайд 57Динамические методы.
Динамические методы описываются с помощью директивы Dynamic. Переопределяются
так же как виртуальные с помощью директивы OVERIDE.
•В список динамических
методов конкретного класса включены только адреса методов, описанных в данном классе. Поиск необходимого метода производится в обратном порядке дерева наследования. Если метод не найден в самом последнем дочернем классе, то поиск продолжается в его предке и так далее до TObject.
Слайд 58Виртуальные методы вызываются максимально быстро, но платой за это является
большой размер системных таблиц, с помощью которых определяются их адреса.
Размер этих таблиц начинает сказываться с увеличением числа классов в иерархии. Динамические методы вызываются несколько дольше, но при этом таблицы с адресами методов имеют более компактный вид, что способствует экономии памяти.
Слайд 59Особой разновидностью методов являются конструкторы и деструкторы.
Создание объекта включает
выделение памяти под экземпляр и инициализацию его полей, а разрушение
- очистку полей и освобождение памяти. Действия по инициализации и очистке полей специфичны для каждого конкретного класса объектов.
Слайд 60По этой причине язык Delphi позволяет переопределить стандартный конструктор Create
и стандартный деструктор Destroy для выполнения любых полезных действий. Можно
даже определить несколько конструкторов и деструкторов (имена им назначает сам программист), чтобы обеспечить различные процедуры создания и разрушения объектов.
Слайд 61Объявление конструкторов и деструкторов похоже на объявление обычных методов с
той лишь разницей, что вместо зарезервированных слов function и procedure
используются слова constructor и destructor. Пример:
type TPeople = class
Name: string;
Family: string;
procedure GetName;
procedure GetFamily;
constructor Create;
destructor Destroy;
end;
Слайд 62Возможная реализация:
Constructor TPeople.Create;
begin
TPeople.Name := ' ';
TPeople.Family := ' ';
end;
Destructor
TPeople.Destroy;
begin
//Пока ничего не делаем
end;
Слайд 63Если объект содержит встроенные объекты или другие динамические данные, то
конструктор - это как раз то место, где их нужно
создавать. Конструктор применяется к классу или к объекту. Конструктор создаёт новый объект только в том случае, если перед его именем указано имя класса. Если указать имя уже существующего объекта, он поведёт себя по-другому: не создаст новый объект, а только выполнит код, содержащийся в теле конструктора.
Слайд 64Если он применяется к классу
People := TPeople.Create;
В динамической памяти
выделяется место для нового объекта.
Выделенная память заполняется нулями.
Затем
выполняются заданные программистом действия конструктора.
Ссылка на созданный объект возвращается в качестве значения конструктора. Тип возвращаемого значения совпадает с типом класса, использованного при вызове (в нашем примере это тип TPeople).
Слайд 65Таким образом, хотя на первый взгляд синтаксис конструктора схож с
вызовом процедуры (не определено возвращаемое значение), но на самом деле
конструктор - это функция, возвращающая созданный и инициализированный объект.
Слайд 66Если конструктор применяется к объекту, People.Create;
то конструктор выполняется
как обычный метод. Другими словами, новый объект не создаётся, а
происходит повторная инициализация полей существующего объекта.
Слайд 67Деструктор уничтожает объект к которому применяется: People.Destroy;
В результате выполняются:
Заданный
программистом код завершения.
Освобождается занимаемая объектом динамическая память.
В теле
деструктора обычно должны уничтожаться встроенные объекты и динамические данные, как правило, созданные конструктором.
Слайд 68Вызов деструктора для несуществующих объектов недопустим и при выполнении программы
приведёт к ошибке. Чтобы избавить программистов от лишних ошибок, в
объекты ввели предоставленный метод Free, который следует вызвать вместо деструктора. Метод Free сам вызывает деструктор Destroy, но только в том случае, если значение объектной переменной не равно nil.
Слайд 69При работе с объектом свойства выглядят как поля: они принимают
значения и участвуют в выражениях. Но в отличии от полей
свойства не занимают место в памяти, а операции их чтения и записи ассоциируются с обычными полями и методами. Это позволяет создавать необходимые сопутствующие эффекты при обращении к свойствам.
Свойства
Слайд 70Объявление свойства выполняется с помощью зарезервированного слова property, например:
type TPeople
= class
FName: string;
procedure GetName;
property Name: string read FName write GetName;
// Свойство
end;
Слайд 71Ключевые слова read и write называются спецификаторами доступа.
После слова
read указывается поле или метод, к которому происходит обращение при
чтении (получении) значения свойства, а после write - поле или метод, к которому происходит обращение при записи (установке) значения свойства. Чтобы имена свойств не совпадали с именами полей, последние принято писать с буквы F.
Слайд 72Обращение к свойствам выглядит в программе как обращение к полям:
var People: TPeople;
Get: string;
...
People.Name := 'Сергей';
Get := People.Name;
Слайд 73Если один из спецификаторов доступа опущен, то значение свойства можно
либо только читать (задан спецификатор read), либо только записывать (задан
спецификатор write). Следующий пример объявлено свойство, значение которого можно только читать:
type TPeople = class
FName: array of string;
function GetName: integer;
property Name: integer read GetName;
end;
function TPeople.GetName: integer;
begin
Result := Length(FName);
end;
Слайд 74В отличии от полей свойства не имеют адреса в памяти,
поэтому к ним запрещено применять операцию @.
Как следствие, их
нельзя передавать в var- и out-параметрах процедур и функций.
Технология объектно-ориентированного программирования в среде Delphi предписывает избегать прямого обращения к полям, создавая вместо этого соответствующие свойства.
Слайд 75Методы получения (чтения) и установки (записи) значений свойств подчиняются определенным
правилам.
Метод чтения свойства - это всегда функция, возвращающая значение
того же типа, что и тип свойства.
Метод записи свойства - это обязательно процедура, принимающая параметр того же типа, что и тип свойства. В остальных отношениях это обычные методы объекта.
Слайд 76Пример методов чтения и записи:
type TPeople = class
FName: boolean;
procedure SetName(const
AName: boolean);
function GetName: integer;
property Name: boolean read FName write SetName;
property
Count: integer read GetName;
end;
Слайд 77Использование методов для получения и установки свойств позволяет проверить корректность
значения свойства, сделать дополнительные вычисления, установить значения зависимых полей и
так далее.
Слайд 78Достоинства ООП
использование при программировании понятий, близких к предметной области;
возможность
успешно управлять большими объемами исходного кода благодаря инкапсуляции, то есть
скрытию деталей реализации объектов и упрощению структуры программы;
возможность многократного использования кода за счет наследования;
сравнительно простая возможность модификации программ;
возможность создания и использования библиотек объектов.
Слайд 79Недостатки ООП
некоторое снижение быстродействия программы, связанное с использованием виртуальных
методов;
идеи ООП не просты для понимания и в особенности для
практического использования;
для эффективного использования существующих объектно-ориентированных систем требуется большой объем первоначальных знаний;
неграмотное применение ООП может привести к значительному ухудшению характеристик разрабатываемой программы.