Занятие 13. Объектно-ориентированный подход (ООП) в программировании
Основные понятия ООП
В настоящее время большое распространение получила технология объектно-ориентированного программирования, у истоков которой стоят такие известные специалисты как Гради Буч, признанный эксперт в этой области.
Этот подход к программированию возник, когда появилось понимание того, что программный код тесно связан с теми данными, которые он обрабатывает. Кроме того, упаковка программного кода в объекты, позволяет посмотреть на программу не как на совокупность программного кода, в виде процедур, функций, и данных, а как на взаимодействие различных объектов, каждый из которых представляет собой совокупность программного кода и данных. Такое понимание программы ближе к представлению предметной области в виде объектов реального мира.
Ключевыми понятиями этой технологии являются понятия объекта и класса. Под классом понимается некая совокупность объектов реального мира, обладающих общими свойствами и общим поведением. Например, класс «Собаки» - объединяет вообще всех собак. Класс «Книги» - объединяет все книги. Класс «Студенты» - объединяет вообще всех студентов. Класс «Планеты» - объединяет все планеты, например, солнечной системы.
Объект представляет собой конкретный экземпляр какого-либо класса, например, собака «Шарик» является объектом класса «Собаки», книга «Три мушкетера» - это объект класса «Книги», а студент Иванов Вася является объектом класса «Студенты», планета «Земля» - объект класса «Планеты».
При описании класса задаются свойства объектов класса и их поведение. Свойства могут задавать внешний вид объекта, его состояние и описываются как данные. Поведение объектов задается с помощью программного кода. При этом разные объекты класса могут иметь разные свойства, но одно и то же поведение. Например, разные планеты солнечной системы могут иметь разное положение на экране, разную окраску, разный размер, но движутся они по одним и тем же законам.
Основные принципы ООП
Объект это нечто, что объединяет в себе данные и программный код. Данные реализованы в виде свойств объекта, программный код это методы объекта. Данные у разных объектов могут различаться, но методы у объектов одного класса едины.
Класс это шаблон, тип, в соответствии с которым строятся конкретные экземпляры объектов класса. Данные объекта должны быть защищены своими методами, т.е. доступ к данным объекта должен осуществляться только через методы объекта. Это первый принцип объектно-ориентрованного программирования, который называется – инкапсуляция. Т.е. данные объекта находятся как бы в капсуле из методов объекта. Этот принцип часто называют сокрытие данных.
Можно создавать наследников класса, при этом наследуются все свойства и методы предка и добавляются свои свойства и методы. Этот принцип носит название – наследование. Это очень мощный принцип, который позволяет не изобретать велосипед, а взять все, что нужно у предка и добавить новое.
Тритий принцип ООП называется – полиморфизм ( поли – много, морф – форма), можно перевести как разнообразие. Этот принцип означает, что родственные объекты могут выполнять схожие по смыслу действия разными способами. Т.е. у потомков поведение уже может быть изменено. Иногда этот принцип называют сокрытие интерфейса, т.е. за одним и тем же заголовком метода, реализующего поведение объекта, скрывается разная реализация метода у предка и у потомка. Чтобы было понятно, рассмотрим такой пример. У класса «Транспортное средство» есть метод «Двигаться». Наследниками этого класса являются классы «Автомобиль», «Самолет» и «Пароход». Наследники наследуют у предка все, в том числе и метод «Двигаться». Для класса «Самолет» двигаться – означает летать, для класса «Пароход» двигаться – означает плыть, для «Автомобиля» двигаться означает ехать. Поэтому в каждом классе наследнике метод «Двигаться» получит свою реализацию.
Перед тем, как перейти непосредственно к описанию синтаксиса классов и объектов в Delphi, полезно будет познакомиться с еще одним типом данных – комбинированным типом или записью.
Тип данных запись (структура)
При описании конкретного человека требуется иметь информацию о его фамилии, имени, годе рождения, поле. Для описания, например, книги, необходима информация о названии книги, авторе, годе издания. Для описания таких данных используется специальный тип данных – запись, который также называют комбинированный тип. Тип данных запись позволяет задавать набор разнородных, но логически связанных данных. Данные, входящие в состав записи, называют полями записи.
Пример объявления типа записи Planet, который описывает данные о планете:
type
Planet = record
Name:string; {название планеты}
x, y:integer; {экранные координаты планеты}
clr:TСolor; {цвет планеты}
rad:integer; {радиус планеты }
end;
Где ключевое слово type задает описание нового типа.
Planet – имя типа;
Name, x,y, clr, rad - это поля типа, каждое из которых описывается со своим типом.
Следующее объявление задает две переменных типа Planet – Earth(Земля) и Mars(Марс).
var
Earth, Mars: Planet;
Доступ к элементам (полям) записи осуществляется с помощью конструкции, называемой "селектор записи", и имеющей следующий общий вид:
R.F
где R – переменная комбинированного типа (запись), F - имя поля.
Пример:
Earth.Name:='Земля';
Mars.Name:='Марс';
Задание для самостоятельной работы
1. Опишите с помощью типа запись данные о книге: название, автор, год издания, цена. Создайте переменную этого типа и присвойте ей значения.
2. Опишите с помощью типа запись данные об учащемся: фамилия, имя, отчество, дата рождения, класс, информация о родителях. Создайте переменную этого типа и присвойте ей значение.
Классы и объекты в Delphi
Грубо говоря, классы можно рассматривать как расширение понятия структура. Поля объекта аналогичны полям записи. Отличие между полями записей и классов состоит в том, что поля записи общедоступны, а поля класса могут иметь разные уровни доступа. Наряду с данными, класс содержит методы. Методы это процедуры или функции. Класс позволяет описать объекты. Объект в Delphi состоит из полей, свойств и методов. Свойства объекта это поля, защищенные своими методами, т.е. доступ к свойству осуществляется не напрямую, а только через методы объекта. Свойство в Delphi описывается как поле, плюс два метода. Один метод позволяет писать в поле, а другой метод – позволяет читать из поля. Таким образом, в Delphi реализован принцип инкапсуляции.
Покажем использование классов, объектов и основных принципов объектно-ориентированного программирования на следующем примере. Например, мы хотим изобразить на экране движение планет вокруг Солнца. Внешний вид окна может быть таким:
Перед тем как писать классы их необходимо спроектировать, а затем оформить в виде операторов языка. В данном примере легко просматриваются следующие классы:
1. Класс «Звезда»;
2. Класс «Планета».
Причем класс «Планета» является наследником класса «Звезда».
У класса «Звезда» могут быть следующие поля и методы:
Поля | Описание |
X,Y | Экранные координаты |
CLR | Цвет звезды |
RP | Радиус звезды |
Метод | Описание |
DRAW | Нарисовать звезду |
CLEAN | Стереть звезду |
MOVE | Переместить звезду |
Для рисования звезды на экране необходим метод Draw, который, используя экранные координаты звезды, рисует ее в нужном месте. Если звезда, находясь в центре экрана, будет неподвижна, тогда зачем же нам методы Clean и Move, которые используются для создания иллюзии движения объекта? Дело в том, что мы будем проектировать класс «Звезда» так, чтобы можно было от него создать наследника, класс «Планета», который унаследует все поля, свойства и методы предка, добавит новые поля и свойства, а некоторые методы предка будут переопределены в потомке. Т.е. методы Clean и Move только объявляются в классе «Звезда», а реализацию они получат в потомке, т.е. будут переопределены, в классе «Планета».
У класса «Звезда» будет только один экземпляр – это «Солнце».
Перейдем к проектированию класса «Планета». Так как класс «Планета» является наследником класса «Звезда», он наследует все поля и свойства у предка и добавляет свои поля и свойства. В таблице показаны поля класса «Планета», которые будут добавлены:
Поля | Описание |
RORB | Радиус орбиты планеты при движении вокруг звезды |
D_UG | Угол поворота планеты при движении по орбите, фактически скорость движения планеты по орбите |
UGOL | Задает начальный угол |
K | Коэффициент растяжения орбиты по оси X |
Заголовки методов у класса «Планета» те же, что и у класса «Звезда». Но метод Draw будет переопределен в классе «Планета», а методы Clean и Move должны получить реализацию.
У класса «Планета» может быть несколько экземпляров: «Земля», «Марс», «Юпитер» и др.
После проектирования можно описать классы с помощью операторов языка. Классы можно описать либо в секции interface, либо на верхнем уровне секции реализации (implementation). Например, класс «Звезда» может иметь следующее описание:
type
TStar = class(TObject)
private
x,y:integer;
col:TColor; // цвет
rp:integer; // радиус планеты
public
constructor Create(x1,y1:integer; col1:TColor; rp1:integer);
procedure draw; virtual;
procedure move; virtual; abstract;
procedure clean; virtual; abstract;
end;
Где ключевое слово type – задает описание класса. TStar – это имя класса. В Delphi имя класса принято начинать с буквы T, что означает type. Ключевое слово class – говорит о том, что описываемый тип – это класс. В скобках задается имя класса, от которого наследуется данный класс. В Delphi все классы являются наследниками класса TObject. Поэтому записи TStar = class(TObject) и TStar = class – равнозначны.
Ключевое слово private – задает скрытые части класса. Доступ к скрытым частям возможен только в рамках данной программной единицы, т.е. того модуля, где содержится описанный класс.
Все методы класса описаны как public(общедоступные), т.е. видимые другими классами.
Ключевое слово virtual, которое используется при описании методов, говорит о том, что данный метод является виртуальным, т.е. этот метод получит другую реализацию у потомков.
Ключевое слово abstract, которое задается при описании методов Clean и Move, говорит о том, что данный метод является абстрактным, т.е. он только объявлен, но не имеет реализации, реализация появится у потомков.
Метод класса Constructor позволяет создать экземпляр класса, т.е. объект, и заполнить значениями его поля. На вход методу поступают значения, которые должны быть присвоены его полям.
Класс «Планета» может иметь следующее описание:
TPlanet=class(TStar)
private
rorb:integer; // радиус орбиты
d_ug:real; // угол поворота
ugol:real; // начальный угол
k:real; // коэффициент растяжения по X
public
constructor CreatePlanet(x1,y1:integer; col1:TColor; rp1:integer;
rorb1:integer; d_ug1,ugol1,k1:real);
procedure clean; override;
procedure draw;override;
procedure move;override;
end;
В части private описываются скрытые части класса – поля, которые добавляются у потомка. В части public описываются общедоступные части класса. Метод CreatePlanet – это конструктор, который позволяет создать экземпляр класса и присвоить начальные значения его полям. Остальные методы описываются с ключевым словом override, которое говорит о том, что данные методы переопределяются в потомке, т.е. получают другую реализацию.
Обратите внимание, при описании классов описываются только заголовки методов. Необходимо еще для каждого метода написать реализацию. Реализация методов задается в части implementation модуля.
Для класса TStar реализация методов имеет следующий вид:
// Конструктор
constructor TStar.Create(x1,y1:integer; col1:TColor; rp1:integer);
begin
x:=x1;
y:=y1;
col:=col1;
rp:=rp1;
end;
// Метод Draw
procedure TStar.Draw;
begin
with form1.canvas do
begin
pen.color:=clBlack;
brush.Color:=col;
ellipse(x-rp,y-rp,x+rp,y+rp);
end;
end;
Для класса TPlanet реализация методов может иметь следующий вид:
// Конструктор
constructor TPlanet.CreatePlanet(x1,y1:integer; col1:TColor; rp1:integer;
rorb1:integer; d_ug1,ugol1,k1:real);
begin
x:=x1; y:=y1; col:=col1; rp:=rp1; rorb:=rorb1; d_ug:=d_ug1; ugol:=ugol1;
k:=k1;
end;
// Метод Draw
procedure TPlanet.draw;
begin
with form1.canvas do
begin
pen.color:=clBlack;
brush.Color:=col;
ellipse(x-rp,y-rp,x+rp,y+rp);
end;
end;
// Метод Clean
procedure TPlanet.clean;
begin
with form1.Canvas do
begin
pen.color:=fon;
brush.Color:=fon;
ellipse(x-rp,y-rp,x+rp,y+rp);
end;
end;
// Метод Move
procedure TPlanet.move;
var x0,y0:integer;
begin
ugol:=ugol+d_ug;
x0:=Form1.width div 2;
y0:=Form1.height div 2;
x:=x0+round(k*rorb*cos(ugol));
y:=y0-round(rorb*sin(ugol));
end;
После описания классов необходимо объявить переменные классов TStar и TPlanet. Это можно сделать либо в секции interface, либо на верхнем уровне секции реализации:
var
Sun:TStar; // переменная-указатель на объект класса TStar
Earth, Mars : TPlanet; // переменные-указатели на объекты класса TPlanet.
Переменная-указатель будет содержать адрес объекта, она только указывает на объект, но объекта еще нет, его нужно создать. Для создания объектов можно использовать событие формы OnCreate. Объекты создаются с помощью конструкторов и для свойств объектов назначаются начальные значения. Обработчик события OnCreate формы может иметь следующий вид:
procedure TForm1.FormCreate(Sender: TObject);
var x1,y1:integer;
begin
randomize;
x1:=Form1.Width div 2;
y1:=Form1.Height div 2;
// Создание объекта класса TStar
Sun:=TStar.Create(x1,y1,clYellow,10);
// Создание объекта Earth
x1:=Form1.Width div 2+round(1.3*20);
y1:=Form1.Height div 2;
Earth:=TPlanet.CreatePlanet(x1,y1,clBlue,5,20, 2*pi/100, 0,1.3);
// Создание объекта Mars
x1:=Form1.Width div 2+round(1.3*60);
y1:=Form1.Height div 2+round(60);
Mars:=TPlanet.CreatePlanet(x1,y1,clRed,3,60,2*pi/70,2,1.3);
end;
Для организации движения поместим в область формы компонент Timer1:TTimer. На событие OnTimer этого компонента напишем обработчик:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
// рисуем планеты в движении
with Earth do begin
clean;
move;
draw;
end;
with Mars do begin
clean;
move;
draw;
end;
end;
Задание для самостоятельной работы
Добавьте еще несколько планет в нашу солнечную систему.
Контрольные вопросы
1. Какие данные позволяет описать тип данных запись?
2. Что такое класс? Что такое объект?
3. Из каких основных элементов состоит объект в Delphi?
4. Чем поля объекта отличаются от полей записи?
5. Что такое свойство и чем оно отличается от поля?
6. Как реализованы методы объектов в Delphi?
7. Перечислите основные принципы объектно-ориентированного программирования.
8. Что такое инкапсуляция? Как в Delphi реализована инкапсуляция?
9. Что такое наследование? Какой объект в Delphi является общим предком всех объектов?
10. Что такое полиморфизм?