Тема: Програмування. Основні етапи розробки прикладних програм

Вид материалаДокументы
Подобный материал:
1   ...   6   7   8   9   10   11   12   13   14
Тема: Об'єктно-орієнтоване програмування.

Тема: Поняття об’єкта.

При побудові складних програм саме складність і була основною проблемою для забезпечення коректності, тому в таких випадках застосовували так звану структуру декомпозиції задач на під задачі, алгоритмів на під алгоритми. Такий поділ дозволяв легко підлагоджувати окремі компоненти, при цьому поділ здійснювався так, щоб окрема частина програми мала якомога повнішу структуру, а для взаємодії з частинами використовувалося мінімуму параметрів. Такий спосіб декомпозиції називається алгоритмічною декомпозицією, тоді всю програму можна представити у вигляді команд вигляду: „візьми дані”, „зроби дію”, „віддай дані”.

З розвитком мов програмування був введений особливий тип даних, який виражав собою дію, тобто поведінку – це процедурний або функціональний тип. Розширивши сферу застосування комбінованих типів (запис) на процедури і функції, отримали новий тип даних, що називається об’єктами. Об’єкти поєднують у собі дві частини: стан, що визначається деяким набором полів даних та поведінку, що визначається набором підпрограм. Таке представлення даних дозволяє будувати програми не як послідовність команд, а як набір дійових осіб (об’єктів). Об’єкти можуть сприймати вплив зовні, певним чином реагувати, тобто проявляти поведінку. Звичайно поведінка залежить від стану об’єкта. Застосування об’єктів становить основу об’єктної декомпозиції і об’єктно-орієнтованого програмування.

Наприклад .Об’єкт-студент (вік, зріст, стать), а поведінка залежить від віку (до 8р. – не курить). Жінки не служать у армії, а чоловіки переважно не носять спідниць, якщо зріст менший 1.50 м в армію не беруть, а при зрості більше 2 м запрошують грати в баскетбол.

Так само як і у звичайному житті, об’єкти програми в залежності від свого початкового стану можуть змінювати свій поточний стан і виливатися на інші об’єкти. Це є теж елемент поведінки.

ООП базується на декількох визначальних принципах: інкапсуляція, наслідування, поліморфізм.

Інкапсуляція – це і є об'єднання в єдину цілу структуру стану об’єкта, полів даних та поведінки (полів підпрограм), сама інкапсуляція реалізується при оголошенні об’єктних типів, які називаються класами об’єктів.

Тема: Оголошення класів об’єктів.

Об’єктові типи (класи) оголошуються в розділі оголошення типів type, при допомозі службового слова object. Сама структура об’єкта подібна до структури даних, тобто слово object замінює слово record, завершується словом end.

Під оголошенням структури розуміється описання в наявних у об’єктів полів даних із заданням їх типу підпрограм, що реалізують поведінку об’єктів. Поля підпрограм в ООП називають методами, при цьому вимагається дотримання наступних правил:
  1. Поля даних оголошуються на початку, а методи після них.
  2. При оголошенні методів у структурі задаються лише заголовок відповідної підпрограми (подібно до інтерфейсу в модулях).
  3. Окремі методи можуть використовувати інші методи цього ж об’єкта, тому вони повинні бути оголошенні в певному порядку.
  4. Реалізація кожного із методів описується нижче оголошення структури класу об’єктів, при цьому як і в модулях в розділі implementation заголовок відповідної підпрограми може бути у скороченій формі без списку формальних параметрів, але ім'я методу матиме складний ідентифікатор <ім'я класу>.<ім'я методу>. Оголошення реалізації методів повинно бути в тому ж розділі описання типів, що й оголошення структури класу..
  5. При оголошенні методів будуть доступними всі поля даних свого класу об’єктів. Це реалізується при допомозі узагальнюючої частини ідентифікаторів методів.

Наприклад. В якості прикладу розглянемо клас об’єктів точка на екрані.

Точка може мати стан, що визначається наступними параметрами:
  1. Координати в графічному режимі.
  2. Колір.
  3. Прапорець активності.

Реалізує наступну поведінку:
  1. Ініціалізація (задання координат та кольору).
  2. Повернення поточних координат, кольору.
  3. Перехід у пасивний чи активний стан.
  4. Рух, або переміщення.

Для прийняття елементів стану та поведінки оголошення структури класу об’єктів „точка” матиме вигляд:

TYPE

POINT=object

x,y:integer;

c:byte;

f:boolean;

PROCEDURE SETCOORD (xx,yy:integer);

PROCEDURE SETCOL (cc:byte);

FUNCTION GETXX: integer;

FUNCTION GETYY: integer;

PROCEDURE ON;

PROCEDURE OFF;

PROCEDURE RUH(dx,dy:integer);

END;

PROCEDURE POINT.SETCOORD;


BEGIN

x:=xx;

y:=yy

END;


PROCEDURE POINT.SETCOL;

BEGIN

c:=cc

END;


FUNCTION POINT.GETXX;

BEGIN

GETXX:=x;

END;


FUNCTION POINT.GETYY;

BEGIN

GETYY:=y;

END;


PROCEDURE POINT.ON;

BEGIN

PutPixel(x,y,c);

f:=true;

END;


PROCEDURE POINT.OFF;

BEGIN

PutPixel(x,y,0);

f:=false;

END;


PROCEDURE POINT.RUH;

BEGIN

OFF;

SETCOORD(x+dx,y+dy);

ON;

END;

Після такого оголошення структури і поведінки в програмі можна описати довільну кількість змінних цього об’єктного типу екземплярів класу POINT. Над цими об’єктами можна виконати певні дії:

VAR

a,b:POINT;

BEGIN

ini; {ініціалізація графіки}

a.SETCOORD(100,100);

a.SETCOL(15);

a.ON;

b.SETCOORD(320,200);

b.SETCOL(9);

b.ON;

z:=ReadKey;

a.RUH(50,50);

z:=ReadKey;

b.RUH(-50,-50);


Зауваження. Всі наведенні вище викладки поки що не демонструють жодної переваги ООП, точніше можна сказати, отримали зворотний ефект, програма стала громісткою. Проте всі ці оголошення матимуть ефект, якщо застосувати наступні визначені принципи ООП: наслідування та поліморфізм.


Тема: Ієрархія об’єктів за принципом наслідування.

Як вже відмічалося об’єктно-орієнтовні програми являють собою поведінку в залежності від стану. Об’єкти можуть належати одному класу, це відповідає ієрархії по складу, або ієрархії об’єктів.

Наприклад. Автомобіль складається з двигуна, трансмісії, шасі, електрообладнання, кузова.

Інший варіант ієрархії називається ієрархією по номенклатурі, або ієрархією класів.

Наприклад. Тепловий двигун – різновид механічної машини, двигун внутрішнього згорання – різновид теплового двигуна, карбюраторний двигун – різновид ДВЗ, двигун ВАЗ2106 – різновид карбюраторного двигуна.

Для побудови ієрархії класів використовують другий визначальний принцип – наслідування, при цьому це відношення пов'язує два класи об’єктів, що називаються відповідно предком та нащадком.

Нащадок успадковує всю структуру предка. Він може мати без власного оголошення ті ж поля даних і методів, окремі методи можуть бути перевизначені. Також можуть бути добавленні нові поля даних і методи. Звузити ж структуру не можна. Це означає, що наслідування дає такий же ж за кількістю полів або ширший клас об’єктів.

При оголошенні нового класу нащадка, описуються тільки нові і перевизначені поля даних. Новий клас будується теж при допомозі службового слова object, після якого в дужках вказується ім'я предка.

На основі класу „точка” можна побудувати декілька класів нащадків, що визначають класи як контури, а з них нові класи фігур, як площі, обмежені цим контуром. Є три ієрархії в глибину і на кожному рівні три класи у ширину. Остання ієрархія буде ієрархією по-складу.

Наприклад. В якості прикладу розглянемо клас нащадок „коло на екрані”, що побудоване від предка „точка”.

Поля даних x,y,c,f повністю успадковуються, потрібно добавити елемент стану радіус, також успадковуються методи, потрібно перевизначити методи ON,OFF, крім цього потрібно добавити методи задання та повідомлення радіусу, таким чином оголошення класу має вигляд:

CIRCLE=object(POINT)

r:integer;

PROCEDURE SETR(rr:integer);

FUNCTION GETR : integer;

PROCEDURE ON;

PROCEDURE OFF;

END;


PROCEDURE CIRCLE.SETR;


BEGIN

r:=rr

END;


FUNCTION CIRCLE.GETR;

BEGIN

GETR:=r

END;


PROCEDURE CIRCLE.ON;

BEGIN

SetColor(c);

Graph.Circle(x,y,r);

f:=true

END;


PROCEDURE CIRCLE.OFF;

BEGIN

SetColor(0);

Graph.Circle(x,y,r);

f:=false

END;


Аналогічним чином можна побудувати наступного нащадка „круг” на основі класу „коло”, при цьому структура класу буде та ж сама, тільки зміниться реалізація двох методів.

Аналогічно класу point можна побудувати класи „прямокутник” та „рівнобедрений трикутник”

VAR

a1,a2:POINT;

b1,b2:CIRCLE;

... ... ...

BEGIN

... ... ...

with a1 do

begin

SETCOORD(100,100);

SETCOL(5);

ON

end;

with b1 do

begin

SETCOORD(200,200);

SETCOL(6);

SETR(20);

ON

end;

a2:=a1;

a2.ON;

b2:=b1;

b2.ON;

a1:=b2;

b1:=a2;

Стосовно даного прикладу можна зробити наступні зауваження:
  1. Подібно до записів в іменах полів даних і методів об’єктів використовують складені ідентифікатори. З метою зменшення кількості узагальнюючого імені об’єкта можна користуватися оператором над записів with do.
  2. Об’єкт-нащадок b1 використовує методи від об’єкта класу точка, а також перевизначений метод ON.
  3. Між об’єктами одного класу можна виконувати операцію присвоєння, при цьому об’єкт, якому присвоюється деяке значення a2, b2 отримує той самий стан, що і об’єкт, від якого здійснюється присвоєння.
  4. При присвоєнні копіюється лише стан, а сама поведінка повинна бути реалізована явним викликом відповідних методів.
  5. Операцію присвоєння можна виконувати не лише між об’єктами одного класу, а також можна виконувати присвоєння між екземплярами різних класів, але якщо вони пов’язані принципом наслідування, причому лише від нащадка до предка і не навпаки. Це означає, що при операції присвоєння, повинні бути передані дані до всіх полів об’єкта, якому присвоюється деяке значення. Надлишок даних від об’єкта, від якого здійснюється присвоєння є несуттєвим.


В розглянутому прикладі вже з'явилися перші прояву ефективності ООП, зокрема побудова ієрархії класів за принципом наслідування. Наслідування дозволило використовувати один раз оголошену структуру батьківського класу у всіх класів нащадка.

Ще один важливий момент ООП пов’язаний із використанням такої властивості об’єктів, як поліморфізм.

Тема: Поліморфізм. Віртуальні методи.

Розглянутий раніше приклад побудови нащадка Circle на перший погляд є довершений і правильним. Особливо ефективним видається метод ruh , який оголошений у структурі класу предка .

Цей метод повністю успадковується нащадками. Реалізація його використовує два методи, що перевизначаються у кожному класі нащадка.

Виконаємо цей метод для двох об’єктів класу point та circle.

VAR

a:POINT;

b:SIRCLE;

BEGIN

... ...

a.SETCOORD(100, 100);

a.SETCOL (5);

a.ON;

a.RUH (50,50)

END.

Така послідовність команд переведе в активний стан об’єкт „точка” в положення з координатами (100,100) з кольором (5), потім починається виконуватися метод рух, який у свою чергу передбачає виклик методів ON, OFF.

Точка переміститься на 50 пікселів вліво і вниз.

b.SETCOORD(200,200);

b.SETR(20);

b.SETCOL(6);

b.ON;

b.RUH(50,50);

Перші чотири оператори відобразять коло радіусом 20 точок за в точці (200, 200) з кольором 6, потім метод рух перемістить раніше розглянуту точку а в центр кола. Таке явище пов’язане із специфічною ситуацією компіляції та виконання програми, що називається раннім зв’язуванням коду методу із іменем об’єкта.

Звернення до ruh призводить до пошуку в межах коду об’єкта в класі circle. Реалізація методу явно відсутній в структурі класу circle, а успадковується від point, то компілятор здійснює пошук коду цього методу у предка. Знайшовши цей метод компілятор передає управління у код об’єкта класу point.

Виконання методу ruh пов’язаний із трьома діями, хоча методи ON i OFF є перевизначеними у circle, проте виявляється, що виконуються не вони, а методи класу предка. Така послідовність дій виключить точку з координатами (150,150) і включить її в координати (200,200), а коло залишиться нерухомим. В цьому випадку не спрацювали перевизначені методи ON та OFF у класі circle. Це пов’язано з тим, що вони входять в реалізацію методу ruh класу point, а отже „жорстко зв’язані” з іменем цього об’єкта (раннє зв’язування).

Якщо ж по-окремо виконати наступні дії:

b.OFF;

b.SETCOORD(50,50);

b.ON;

то дійсно переміститься коло. В цьому випадку спрацюють власні методи, оскільки вони пов’язані з іменем об’єкта b.

Щоб уникнути подібної ситуації, пов’язаної з раннім зв’язуванням кодів перевизначених методів з іменами даних об’єктів, використовують віртуальні методи. В даному випадку віртуальними методами мають бути ON і OFF.

TYPE


POINT=object

x,y:integer;

c:byte;

f:boolean;

PROCEDURE SETCOORD (xx,yy:integer);

PROCEDURE SETCOL (cc:byte);

FUNCTION GETXX: integer;

FUNCTION GETYY: integer;

PROCEDURE ON; virtual;

PROCEDURE OFF;virtual;

PROCEDURE RUH(dx,dy:integer);

END;

Віртуальні методи вже будуть працювати по-своєму для кожного класу, тобто при виклику методу b.RUH, спочатку відбудеться передача управління у код об’єкта класу point, оскільки перший із методів у реалізації RUH є перевизначеним віртуальним методом OFF , то відбудеться повернення у код об’єкта класу circle (спрацьовує власний OFF ).

Код віртуального методу не зв’язується з іменем об’єкта на етапі компіляції. Для віртуальних методів формується так званий пізній зв’язок на етапі виконання програми, в залежності від того, у якому контексті цей метод викликається.

Використання віртуальних методів передбачає декілька стандартних правил:
  1. Віртуальним варто оголошувати лише той метод, який:

а). перевизначається у кожному нащадку, тобто в кожному працює по-своєму;

б). входить у склад реалізації іншого методу у предку;

в). містить у реалізації віртуальній, має успадкуватися нащадками без пере визначення.
  1. Один раз віртуальний – все життя віртуальний”. Це означає, що на деякому рівні ієрархії класів певний метод був оголошений віртуально, то на всіх нижчих видів ієрархії, тобто у всіх нащадках цей метод повинен перевизначеним і віртуальним.

Віртуальні методи можуть працювати дійсно як віртуальні або як звичайні методи. Необхідний режим пізнього зв’язування, якщо ж цього режиму немає, то віртуальний метод працює як звичайно.

Тема: Конструктори та деструктори.

Вище було сказано, що віртуальність методу залежить від режиму зв’язування коду методу із іменем об’єкта. Перемикання режимів раннього і пізньог7о зв’язування здійснюється за допомогою застосування спеціальних методів, що називаються конструкторами та деструкторами.

Метод конструктор використовується для активізації режиму пізнього зв’язування, після явного виклику одного із конструкторів деякого об’єкта. Всі методи, які оголошуються як віртуальні будуть працювати як віртуальні.

Конструктор оголошується за допомогою службового слова CONSTRUCTOR, що замінює procedure або function відповідно. Все решта в оголошенні методу залишається без змін.

В якості конструктора переважно використовують якийсь із ініціалізуючих методів об’єкта, проте конструктор може мати пусту ініціалізацію, тобто цей метод нічого не робить, окрім включення пізнього зв’язування.

TYPE


POINT=object

x,y:integer;

c:byte;

f:boolean;

CONSTRUCTOR INIT;

... ... ... ...

END;


CONSTRUCTOR POINT.INIT;

BEGIN

END;

Використання конструкторів повинно здійснюватися згідно наступних правил:
  1. Конструкторів може бути декілька у одного об’єкта. Явний виклик будь-якого з них ініціалізує режим пізнього зв’язування.
  2. Конструктором варто вибирати, або ініціалізуючий метод, або пустий.
  3. Конструктор не може бути віртуальним.
  4. Конструктори можуть успадковуватися при наслідуванні.
  5. Конструктор включає пізнє зв’язування лише для „свого” об’єкта.

Оскільки режим пізнього зв’язування дещо сповільнює роботу програми і збільшує код, то цей режим варто виключати лише при необхідності. Для закриття режиму пізнього зв’язування використовується ще один вид методів - деструктор.

Оголошується деструктор за допомогою службового слова DESTRUCTOR. Це слово замінює відповідно слово procedure або function у заголовку відповідного методу. Як і конструктор деструктор може бути один з значущих методів, який виконує деяку завершальну операцію об’єкта. Також деструктор може бути пустим, тоді його основне призначення закрити режим пізнього зв’язування.

Застосування деструктора варто проводити згідно з наступними правилами:
  1. Деструкторів у об’єкта може бути декілька. Пізнє зв’язування закривається явним викликом будь-якого з них.
  2. В якості деструктора варто вибирати, або завершальний метод, або пустий метод.
  3. Деструктор може бути віртуальним.
  4. Деструктори можуть успадковуватися за принципом наслідування.
  5. Свій режим зв’язування у об’єкта закриває свій деструктор.

Таким чином для реалізації методу рух у попередньому прикладі потрібно, щоб оголошення структури класу point або circle мало наступний вигляд:

TYPE

POINT=object

x,y:integer;

c:byte;

f:boolean;

CONSTRUCTOR INIT;

PROCEDURE SETCOORD (xx,yy:integer);

PROCEDURE SETCOL (cc:byte);

FUNCTION GETXX: integer;

FUNCTION GETYY: integer;

PROCEDURE ON; virtual;

PROCEDURE OFF;virtual;

PROCEDURE RUH(dx,dy:integer);

DESTRUCTOR DONE;

END;


CIRCLE=object(POINT)

r:integer;

PROCEDURE SETR(rr:integer);

FUNCTION GETR : integer;

PROCEDURE ON; VIRTUAL;

PROCEDURE OFF; VIRTUAL;

END;

... ... ...

{реалізація методів}


VAR

a:POINT;

b:CIRCLE;

BEGIN


b.SETCOORD(200,200);

b.SETCOL(9);

b.SETR(20);

b.INIT;

b.RUH(50,50);

b.DONE;

END.