Помощничек
Главная | Обратная связь


Археология
Архитектура
Астрономия
Аудит
Биология
Ботаника
Бухгалтерский учёт
Войное дело
Генетика
География
Геология
Дизайн
Искусство
История
Кино
Кулинария
Культура
Литература
Математика
Медицина
Металлургия
Мифология
Музыка
Психология
Религия
Спорт
Строительство
Техника
Транспорт
Туризм
Усадьба
Физика
Фотография
Химия
Экология
Электричество
Электроника
Энергетика

Робота з базами данних в Delphi



КУРС ЛЕКЦІЙ

з дисципліни

“Середовище розробки програм”

для студентів всіх форм навчання

спеціальності 6.091502 “Системне програмування”

 

 

Київ-Черкаси 20010


 

Зміст

1 Об‘єктно-орієнтоване програмування

Складові класу

Оголошення класу

Огляд палітри компонентів

Стандартні компоненти

Сторінки additional та system

Обробка виняткових ситуацій у Delphi

Структурна обробка виняткових ситуацій

Модель виняткових ситуацій у Delphi

Синтаксис обробки виняткових ситуацій

Приклади обробки виняткових ситуацій

Виклик виняткової ситуації

Доступ до екземпляра об'єкта exception

Визначені оброблювачі виняткових ситуацій

Виключення, що виникають при роботі з базами даних

Графічні можливості Delphi

Робота з базами данних в Delphi


1 ОБ‘ЄКТНО-ОРІЄНТОВАНЕ ПРОГРАМУВАННЯ

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

У даному визначенні можна виділити три частини: 1) OOP використовує як базові елементи об'єкти, а не алгоритми (ієрархія "бути частиною", що була визначена в главі 1); 2) кожен об'єкт є екземпляром якого-небудь визначеного класу; 3) класи організовані ієрархічно (див. поняття про ієрархію "is а" там же). Програма буде об’єктно-орієнтованою тільки при дотриманні всіх трьох зазначених вимог. Зокрема, програмування, не засноване на ієрархічних відносинах, не відноситься до OOP, а називається програмуванням на основі абстрактних типів даних.

Чому програмному забезпеченню притаманна складність?

Складність викликається 5 основними причинами:

– складністю реальної предметної області, з якої виходить замовлення на розробку;

– труднощами керування процесом розробки;

– необхідністю забезпечити достатню гнучкість програми;

– незадовільними способами опису поводження великих дискретних систем.

Складність реального світу. Проблеми, що ми намагаємося вирішити за допомогою програмного забезпечення, часто неминуче містять складні елементи, а до відповідного програмам пред'являється безліч різних, часом взаємовиключних вимог. Розглянемо необхідні характеристики електронної системи багатомоторного літака, стільникової телефонної комутаторної системи і робота. Досить важко зрозуміти, навіть загалом, як працює кожна така система. Тепер додайте до цьому додаткові вимоги (які часто не формулюються явно), такі як зручність, продуктивність, вартість, виживаність і надійність! Складність задачі і породжує складність програмного продукту.

Ця зовнішня складність звичайно виникає через "нестиковку" між користувачами системи і її розроблювачів: користувачі з працею можуть пояснити у формі, зрозумілої розроблювачам, що насправді потрібно зробити. Бувають випадки, коли користувач лише смутно представляє, що йому потрібно від майбутньої програмної системи. Це в основному відбувається не через помилки з тієї чи іншої сторони; просто кожна з груп спеціалізується у своїй області, і їй бракує знань партнера. У користувачів і розроблювачів різні погляди на сутність проблеми, і вони роблять різні висновки про можливі шляхи її рішення. Насправді, навіть якщо користувач точно знає, що йому потрібно, ми важко можемо однозначно зафіксувати всі його вимоги. Звичайно вони відбиті на багатьох сторінках тексту, "розведених" деякими малюнками. Такі документи важко піддаються розумінню, вони відкриті для різних інтерпретацій і часто містять елементи, що відносяться скоріше до дизайну, чим до необхідних вимог розробки.

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

Труднощі керування процесом розробки. Основне завдання розроблювачів полягає в створенні ілюзії простоти, у захисті користувачів від складності описуваного предмета чи процесу. Розмір вихідних текстів програмної системи аж ніяк не входить у число її головних достоїнств, тому ми намагаємося робити вихідні тексти більш компактними, винаходячи хитромудрі і могутні методи, а також використовуючи середовища розробки вже існуючих проектів і програм. Однак нові вимоги для кожної нової системи неминучі, а вони приведуть до необхідності або створювати багато програм "з нуля", або намагатися по-новому використовувати існуючі. Всього 20 років тому програми обсягом у кілька тисяч рядків на ассемблері виходили за межі наших можливостей. Сьогодні звичайними стали програмні системи, розмір яких обчислюється десятками тисяч навіть чи мільйонами рядків на мовах високого рівня. Жодна людина ніколи не зможе цілком зрозуміти таку систему. Навіть якщо ми правильно розкладемо її на складові частини, ми все рівно одержимо сотні, а іноді і тисячі окремих модулів. Тому такий обсяг робіт зажадає залучення команди розроблювачів, в ідеалі як можна меншої по чисельності. Але який би вона не була, завжди будуть виникати значні труднощі, зв'язані з організацією колективної розробки. Чим більше розроблювачів, тим складніше зв'язку між ними і тем складніше координація, особливо якщо учасники робіт географічно видокремлені друг від друга, що типово у випадку дуже великих проектів. Таким чином, при колективному виконанні проекту головною задачею керівництва є підтримка єдності і цілісності розробки.

Гнучкість програмного забезпечення. Будівельна компанія звичайно не має власного лісгоспу, який би їй поставляв ліс для пиломатеріалів; зовсім незвичайно, щоб монтажна фірма спорудила свій завод для виготовлення сталевих балок під майбутній будинок. Однак у програмній індустрії така практика - справа звичайна. Програмування має граничну гнучкість, і розроблювач може сам забезпечити себе всіма необхідними елементами, що відносяться до будь-якого рівня абстракції. Така гнучкість надзвичайно приваблива. Вона змушує розроблювача створювати самотужки всі базові будівельні блоки майбутньої конструкції, з яких складаються елементи більш високих рівнів абстракції. На відміну від будівельної індустрії, де існують єдині стандарти на багато конструктивних елементів і якість матеріалів, у програмній індустрії таких стандартів майже немає. Тому програмні розробки залишаються дуже трудомісткою справою.

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

Усередині великої прикладної програми можуть існувати сотні і навіть тисячі перемінних і кілька потоків керування. Повний набір цих перемінних, їхній поточних значень, що тече адреси і стека виклику для кожного процесу описує стан прикладної програми в кожен момент часу. Тому що виконання нашої програми здійснюється на цифровому комп'ютері, ми маємо систему з дискретними станами. Аналогові системи, такі, як рух кинутого м'яча, навпроти, є безупинними. Д. Парнас [4] пише: "коли ми говоримо, що система описується безупинною функцією, ми маємо через, що в ній немає схованих сюрпризів. Невеликі зміни вхідних параметрів завжди викликають невеликі зміни вихідних". З іншого боку, дискретні системи по самій своїй природі мають кінцеве число можливих станів, хоча у великих системах це число відповідно до правил комбінаторики дуже велико. Ми намагаємося проектувати системи, розділяючи їх на частині так, щоб одна частина мінімально впливало на іншу. Однак переходи між дискретними станами не можуть моделюватися безупинними функціями. Кожна подія, зовнішнє стосовно програмної системи, може перевести її в новий стан, і, більш того, перехід з одного стану в інше не завжди детермінований. При несприятливих умовах зовнішня подія може порушити поточний стан системи через те, що її творці не змогли передбачити всі можливі варіанти. Уявимо собі пасажирський літак, у якому система керування польотом і система електропостачання об'єднані. Було б дуже неприємно, якби від включення пасажиром, що сидить на місці 38J, індивідуального висвітлення літак негайно ввійшов би в глибоке піку. У безупинних системах таке поводження було б неможливим, але в дискретних системах будь-яка зовнішня подія може вплинути на будь-яку частину внутрішнього стану системи. Це, мабуть, і є головною причиною обов'язкового тестування наших систем; але справа в тім, що за винятком самих тривіальних випадків, усеосяжне тестування таких програм провести неможливо. І поки в нас немає ні математичних інструментів, ні інтелектуальних можливостей для повного моделювання поводження великих дискретних систем, ми повинні задовольнитися розумним рівнем впевненості в їхній правильності.

Наслідок необмеженої складності

"Чим складніше система, тим легше її цілком розвалити". Будівельник навряд чи погодиться розширити фундамент уже побудованого 100-поверхового будинку. Це не просто дорого: робити такі речі значить напрошуватися на неприємності. Але що дивно, користувачі програмних систем, не задумуючись, ставлять подібні задачі перед розроблювачами. Це, затверджують вони, усього лише технічне питання для програмістів.

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

Канонічна форма складної системи. Виявлення загальних абстракцій і механізмів значно полегшує розуміння складних систем. Наприклад, досвідчений пілот, зорієнтувавшись усього за кілька хвилин, може взяти на себе керування багатомоторним реактивним літаком, на якому він раніш ніколи не літав, і спокійно його вести. Визначивши елементи, загальні для всіх подібних літаків (такі, як кермо керування, елерони і дросельний клапан), пілот потім знайде відмінності цього конкретного літака від інших. Якщо пілот уже знає, як керувати одним літаком визначеного типу, йому набагато легше навчитися керувати іншим схожим літаком.

Цей приклад наводить на думку, що ми зверталися з терміном ієрархія в дуже приблизному змісті. Найбільш цікаві складні системи містять багато різних ієрархій. У літаку, наприклад, можна виділити кілька систем: харчування, керування польотом і т.д. Така розбивка дає структурну ієрархію типу "бути частиною". Цю же систему можна розкласти зовсім іншим способом. Наприклад, турбореактивний двигун - особливий тип реактивного двигуна, a "Pratt and Whitney TF30" - особливий тип турбореактивного двигуна. З іншого боку, поняття "реактивний двигун" узагальнює властивості, властивим усім реактивним двигунам; "турбореактивний двигун" - це просто особливий тип реактивного двигуна з властивостями, що відрізняють його, наприклад, від прямоточного.

Ця друга ієрархія являє собою ієрархію типу "is-a". Виходячи з нашого досвіду, ми визнали за необхідне розглянути систему з двох точок зору, як ієрархію першого і другого типу. назвемо ці ієрархії відповідно структурою класів і структурою об'єктів.

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

Структури класів і об'єктів системи разом ми називаємо архітектуроюсистеми.

Алгоритмічна декомпозиція. Більшість з нас формально навчено структурному проектуванню "зверху вниз", і ми сприймаємо декомпозицію як звичайний поділ алгоритмів, де кожен модуль системи виконує один з етапів загального процесу.

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

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

ООП пропонує новий підхід до розробки програмного забезпечення призначеного для рішення задач підвищеної складності.

Звичайно на мовах ООП пишуть складні системи, що включають у себе різні рівні абстракції. Фундаментальна концепція ООП складається в передачі повідомлень об'єктів. Для цього необхідно щоб об'єкти визначалися разом з повідомленнями, на які вони будуть реагувати (у процедурах мов програмування визначалися спочатку функції, потім дані, що будуть їм передаватися).

Існують 5 компонент ООП:

1) Об'єкт;

2) Повідомлення;

3) Клас;

4) Спадкування;

5) Метод.

 

Визначення кожного з компонентів містить у собі визначення інших, тобто всі ці компоненти тісно зв'язані один з одним.

ОО мови програмування повинні мати властивості:

- абстракції;

- інкапсуляції;

- спадкування;

- поліморфізму.

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

Об'єкт являє собою інкапсульовану абстракцію, що відображає його внутрішній стан.

Спосіб яким об'єкт обробляє повідомлення, залежить не тільки від повідомлення, але і від стану самого об'єкта, ця властивість у ООМ реалізовано поліморфізмом.

Об'єкт має чітко визначений опис повідомлення, яке він приймає і методи, що показують, як обробити повідомлення.

Опис кожного методу унікально.

Приклади ОО мов програмування:

Сама несуперечлива ООМ Small Talk (він практично не використовується), Clos, C++, ADA, Delphi, ...

Кроки програмування при написанні великої системи.

1) Вивчення предметної області і визначення основних об'єктів для рішення даної задачі;

2) Визначення закритого даного, даного стану для цих об'єктів;

3) Визначення другорядних об'єктів і їхніх захищених даних;

4) Розробка ієрархії класів, що представляють об'єкти;

5) Ідентифікація ключових повідомлень, що повинні обробляти об'єкти кожного класу;

6) Розробка початкової послідовності виражень, що представляють рішення проблеми на високому рівні;

7) Розробка методів, що обробляють усі повідомлення;

8) Очищення проекту.

 

Класи - це особливий “винахід” програмістів для спрощення розробки складних програм і поліпшення їхньої якості. В основі класів лежать три фундаментальних принципи, що називаються інкапсуляція, спадкування і поліморфізм.

Інкапсуляція

Клас являє собою єдність трьох сутностей - полів, методів і властивостей. Об'єднання цих сутностей у єдине ціле і називається інкапсуляцією. Інкапсуляція дозволяє багато в чому ізолювати клас від інших частин програми, зробити його “самодостатнім” для рішення конкретної задачі. У результаті клас завжди несе в собі деяку функціональність. Наприклад, клас ТForm містить (інкапсулює в собі) усе необхідне для створення Windows-вікна, клас TMemo являє собою полнофункціональний текстовий редактор, клас TTimer забезпечує роботу програми з таймером і т.д.

Інкапсуляція являє собою могутній засіб обміну готовими до роботи програмними заготівлями.

Спадкування

Любою клас може бути породжений від іншого класу. Для цього при його оголошенні вказується ім'я класу-батька:

TChildClass =class (TParentClass)

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

Усі класи Object Pascal породжені від єдиного батька класу TObject. Цей клас не має полів і властивостей, але містить у собі методи самого загального призначення, що забезпечують весь життєвий цикл будь-яких об'єктів - від їхнього створення до знищення. Програміст не може створити клас, що не був би дочірнім класом TObject. Наступні два оголошення ідентичні:

TaClass = class(TObject) TaClass =class

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

Для приклада клас Tpersistent збагачує можливості свого батька TObject: він “уміє” зберігати дані у файлі й одержувати їх з нього, у результаті це вміють робити і весь його нащадки. Клас TComponent, у свою чергу, уміє взаємодіяти із середовищем розроблювача і передає це уміння своїм нащадкам. Tcontrol не тільки здатний працювати з файлами і середовищем розроблювача, але він ще вміє створювати й обслуговувати видимі на екрані зображення, а його нащадок TWinControi може створювати Windows-вікна і т.д.

Рис. 9.1. Фрагмент дерева класів Object Pascal

Поліморфізм

Поліморфізм - це властивість класів вирішувати схожі за змістом проблеми різними способами. У рамках Object Pascal поведінкові властивості класу визначаються набором вхідних у нього методів. Змінюючи алгоритм того чи іншого методу в нащадках класу, програміст може додавати цим нащадкам відсутні в батька специфічні властивості. Для зміни методу необхідно перекрити його в нащадку, тобто оголосити в нащадку однойменний метод і реалізувати в ньому потрібні дії. У результаті в об'єкті-батьку й об'єкті-нащадку будуть діяти два однойменних методи, що мають різну алгоритмічну основу і, отже, що додають об'єктам різні властивості. Це і називається поліморфізмом об'єктів.

У Object Pascal поліморфізм досягається не тільки описаним вище механізмом спадкування і перекриття методів батька, але і їх віртуалізацією, що дозволяє батьківським методам звертатися до методів своїх нащадків.

СКЛАДОВІ КЛАСУ

Поля

Полями називаються інкапсульовані в класі дані. Поля можуть бути будь-якого типу, у тому числі - класами, наприклад:

typeTMyClass =class

aIntField: Integer;

aStrField:String;

aObjField: TObject;

end;

Кожен об'єкт одержує унікальний набір полів, але загальний для всіх об'єктів даного класу набір методів і властивостей. Фундаментальний принцип інкапсуляції вимагає звертатися до полів тільки за допомогою методів і властивостей класу. Однак у Object Pascal дозволяється звертатися до полів і прямо:

Type

TMyClass =class

FIntField: Integer;

FStrField: String; end;

Var

aObject: TMyClass;

Begin

aObject.FIntField := 0;

aObject.FStrField := 'Рядок символів';

end;

Клас-нащадок одержує всі полючи усіх своїх предків і може доповнювати їх своїми, але він не може перевизначати їхній чи видаляти.

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

Методи

Инкапсульовані в класі процедури і функції називаються методами. Вони з'являються так само, як і звичайні підпрограми:

Type

TMyClass =class

Function MyFunc(aPar: Integer): Integer;

Procedure MyProc;

end;

Доступ до методів класу, як і до його полів, можливий за допомогою складених імен:

Var

aObject: TMyClass;

Begin

aObject.MyProc;

end;

Як уже говорилося, методи класу можуть перекриватися в нащадках. Наприклад:

Type

TParentClass =class Procedure DoWork;

end;

TChildClass = class(TParentClass) Procedure DoWork;

end;

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

У Object Pascal набагато частіше використовується динамічне заміщення методів на етапі прогону програми. Для реалізації цей метод, що заміщається в батьківському класі, повинний з'являтися як динамічний (з директивою dynamic) чи віртуальний (virtual). Зустрівши таке оголошення, компілятор створить дві таблиці -DMT (Dynamic Method Table) і VMT (Virtual Method Table) і помістить у них адреси точок входу відповідно динамічних і віртуальних методів. При кожнім звертанні до методу, що заміщається, компілятор уставляє код, що дозволяє витягти адресу крапки входу в підпрограму з тієї чи іншої таблиці. У класі-нащадку метод, що заміщується, з'являється з директивою override (перекрити). Одержавши цю вказівку, компілятор створить код, що на етапі прогону програми помістив у батьківську таблицю точку входу методу класу-нащадка, що дозволить батьку виконати потрібну дію за допомогою нового методу.

Нехай, наприклад, батьківський клас за допомогою методів show і Hide відповідно показує чи ховає щось на екрані зображення. Для створення зображення він використовує метод Draw з логічним параметром:

Type

TVisualObject = class(TWinControl)

Procedure Hide;

Procedure Show;

Procedure Draw(IsShow: Boolean);virtual;

end;

TVisualChildObject = class(TVisualObject)

Procedure Draw(IsShow: Boolean);override;

end;

Реалізація методів show і Hide дуже проста:

Procedure TVisualObject.Show;

Begin

Draw(True) ;

end;

Procedure TVisualObject.Hide;

Begin

Draw(False) ;

end;

Методи Draw у батька і нащадка мають різну реалізацію і створюють різні зображення. У результаті батьківські методи show і Hide - ховати чи показувати ті чи інші зображення будуть у залежності від конкретної реалізації методу Draw у-кожного зі своїх нащадків. Динамічне зв'язування повною мірою реалізує поліморфізм класів.

Різниця між динамічними і віртуальними методами полягає в тому, що таблиця динамічних методів DMT містить адреси тільки тих методів, що оголошені як dynamic у даному класі, у той час як таблиця VMT містить адреси віртуальних методів не тільки даного класу, але і всіх його батьків. Значно більше по розмірі таблиця VMT забезпечує більш швидкий пошук, у той час як при звертанні до динамічного методу програма спочатку переглядає таблицюDMT в об'єкта, потім -у його батьківського класу і так далі, поки не буде знайдена потрібна крапка входу.

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

Type

TVisualObject = class(TWinControl)

Procedure Draw(IsShow: Boolean);virtual; abstract;

end;

TVisualChildObject = class(TWinControl)

Procedure Draw(IsShow: Boolean);override; end;

Var

aVisualObject: TVisualObject;

aVisualChild: TVisualChildObject ;

Begin

aVisualObject.Show; {Помилка/ Звертання до абстрактного методу}
aVisualChild.Show;
{Нормальне звертання. Метод Draw у класу TVisualChildObject перекритий.)

end;

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

До складу будь-якого класу входять два спеціальних методи -конструктор і деструктор. У класу TObject ці методи називаються create і Destroy, так само вони називаються в переважній більшості його нащадків. Конструктор розподіляє об'єкт у динамічній пам'яті і поміщає адресу цієї пам'яті в перемінну self, що автоматично з'являється в класі. Деструктор видаляє об'єкт із купи. Звертання до конструктора повинне випереджати будь-яке звертання до полів і деяких методів об'єкта. За своєю формою конструктори і деструктори є процедурами, але з'являються за допомогою зарезервованих слів constructor і Destructor:

Type

TMyClass =classIntField: Integer; Constructor Create(Value: Integer);

Destructor Destroy;

end;

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

Var

MyObject: TMyClass;

Begin

MyObject.IntField := 0;

{ Помилка! Об'єкт не створений конструктором!}

MyObject := TMyClass.Create;

// Треба так: створюємо об'єкт

MyObject.IntField := 0;

// і звертаємося до його поля

MyObect.Free;

// Знищуємо непотрібний об'єкт

end;

У базовому класі TObject визначений метод Free, що спочатку перевіряє дійсність адреси об'єкта і лише потім викликає деструктор Destroy. Звертання до деструктора об'єкта буде помилковим, якщо об'єкт не створений конструктором, тому для знищення непотрібного об'єкта варто викликати метод Free, як це зроблено в попередньому прикладі.

Більшість конструкторів реалізують деякі дії, необхідні для правильної роботи об'єкта. Тому в конструкторі класу-нащадка варто спочатку викликати конструктор свого батька, а вже потім здійснювати додаткові дії. Виклик будь-якого методу батьківського класу досягається за допомогою зарезервованого слова inherited (успадкований):

Constructor TMyClass.Create(Value: Integer);

// Можлива реалізація конструктора

begin

Inherited Create; // Викликаємо успадкований конструктор IntField := Value; // Реалізуємо додаткові дії

end;

Деякі методи можуть викликатися без створення й ініціації об'єкта. Такі методи називаються методами класу, вони з'являються за допомогою зарезервованого слова class:

Type

TMyClass = class(TObject)

class Function GetClassName:String;

end;

Var

S: String;

Begin

S := TMyClass.GetClassName;

end;

Методи класу не повинні звертатися до полів, тому що в загальному випадку викликаються без створення об'єкта, а отже, у момент виклику полів просто не існує. Звичайно вони повертають службову інформацію про клас - ім'я класу, ім'я його батьківського класу, адреса методу і т.п.

 

Властивості

Властивості - це спеціальний механізм класів, що регулює доступ до полів. Властивості з'являються за допомогою зарезервованих слів property, read і write (слова read і write вважаються зарезервованими тільки в контексті оголошення властивості). Звичайна властивість зв'язана з деяким полем і вказує ті методи класу, що повинні використовуватися при записі в це чи поле при читанні з нього. Наприклад:

Type

TaClass =class

IntField: Integer; Function GetField: Integer;

Procedure SetField (Value: Integers);

Property IntegerValue: Integerread GetField

write SetField;

end;

У контексті програми властивість поводиться як звичайне поле. Наприклад, ми могли б написати такі оператори:

Var

aClass: TaClass;

Value: Integer;

Begin

aClass := TaClass.Create; { Обов'язкове звертання до

конструктору перед звертанням до поля чи властивості!} aClass.IntegerValue := 0;

Value := aClass.IntegerValue;

aClass.Destroy; // Видалення непотрібного об'єкта

end;

Більш того, можливий і такий оператор присвоювання:

aClass.IntField := NewValue;

Різниця між цим оператором і оператором

aClass.IntegerValue := NewValue;

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

IbOutput.Caption := 'Рядок';

Властивість Caption компонента Label викликає метод setText, що не тільки запам'ятовує рядок символів у внутрішньої перемінний, але і здійснює промальовування мітки з новим текстом.

Якщо немає необхідності в спеціальних діях при читанні чи записі властивості, замість імені відповідного методу можна вказувати ім'я поля:

Type

TaClass =classIntFiled: Integer;

Procedure SetFieid (Value: Integers;

Property IntegerValue:

Integerread IntFiledwrite SetFieid;

end;

Якщо необхідно, щоб властивість була доступна тільки для читання чи тільки для запису, варто опустити відповідно частина write чи read. Взагалі говорячи, властивість може і не зв'язуватися з полем. Фактично воно описує один чи два методи, що здійснюють деякі дії над даними того ж типу, що і властивість.

 

ОГОЛОШЕННЯ КЛАСУ

 

Любою знову створюваний клас може містити секції (розділи), обумовлені зарезервованими словами published(опубліковані), private (закриті), protected (захищені), public(доступні) і automated(автоматизовані). Усередині кожної секції спочатку визначаються поля, а потім - методи і властивості.

Секції визначають області видимості елементів опису класу. Секція public не накладає обмежень на область видимості полів, що перелічуються в ній, методів і властивостей - їхній можна викликати в будь-якому іншому модулі програми. Секція published також не обмежує область видимості, однак у ній перелічуються властивості, що повинні бути доступні не тільки на етапі виконання, але і на етапі конструювання програми (тобто у вікні Інспектора об'єктів). Секція published використовується тільки при розробці нестандартних компонентів. Замітаю, що середовище Delphi поміщає опису компонентів, вставлених у форму, у спеціальну секцію без назви, що розташовується відразу за заголовком класу і продовжується до першої оголошеної секції. Ця секція - published. Програмісту не слід поміщати в неї власні елементи опису чи класу видаляти з її елементи, уставлені середовищем. Секція private звужує область видимості до мінімуму: закриті елементи описи доступні тільки усередині методів даного класу і підпрограмах, що знаходяться в тім же модулі, де описаний клас. Елемент, оголошений у секції private, стає недоступним навіть найближчим нащадкам класу, якщо вони розміщаються в інших модулях. Секція protected доступна тільки методам самого класу, а також будь-яким його нащадкам, незалежно від того, чи знаходяться вони в тім же чи модулі ні. Нарешті, секція automated використовується тільки для оголошення властивостей і методів, що будуть додані до так називаного інтерфейсу OLE-об'єктів Автоматизації; область видимості членів цієї секції не обмежена.

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

Наступний фрагмент коду пояснює області видимості.

Unit Unit1;

Interface

Uses Controls, Forms;

Type

TForm= class(TForm)

Buttoni: TButton; // Ця секція обслуговується Delphi

// Її елементи доступні усім
// Ця секція доступна в модулі Uniti

private
FIntField: Integers
Procedure SetValue(Value: Integers);
Function GetValue: Integer;
published
// Ця секція доступна в будь-якому модулі

Property IntField:read GetValuewrite SetValue;

protected // Ця секція доступна класам-нащадкам

Procedure Proc1;

public // Ця секція доступна в будь-якому модулі Procedure Proc2;

end;

Var

Formi: TForm1;

Implementation Procedure TForm.Proc1 ;

Buttoni.Color := clBtnFace;1

// Так можна

FIntField := 0;

// Так можна

IntField := 0;1

// Так можна Proc1;

// Так можна Proc2;1

// Так можна

end;

Begin

Form1.Button1.Color := clBtnFace; // Так можна

Form1.FIntField := 0; // Так можна

Form1.IntField := 0; // Так можна
Form1.Proc1; // Так не можна!
Form1.Proc2; // Так можна

End.

Unit Unit2;

Interface

Uses Controls, Unit1;

Type

TForm2 = class(TFormI) Button2: TButton;

Procedure Button2Click(Sender: TObject);

end;

Var

Form2: TForm2;

Implementation

Procedure TForm2.Button2Click(Sender: TObject);

Begin

Buttoni.Color := clBtnFace; // Так можна

Fіn'tFіеld := 0; // Так не можна!

IntField := 0; // Так можна

Proc1; // Так можна

Proc2; // Так можна

end;

Begin

Form1.Buttoni.Color := clBtnFace; // Так можна

Form1.FIntField := 0; // Так не можна!

Form1.IntField := 0; // Так можна

Form1.Proc1; //Так не можна!

Form1.Proc2; // Так можна

End.

При оголошенні класу-нащадка дозволяється переміщати елементи класу з однієї області видимості в іншу. Для попереднього приклада припустиме таке оголошення:

Type

TForm2 = class(Tform1)

Public

Procedure Proc1;

end;

Після цього в модулі unit2 можливо таке звертання:

Form2.Proc1;

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

Клас може з'являтися тільки в інтерфейсній області модуля чи на самому початку області реалізації. Не можна визначати класи в розділі описів підпрограм.

 

Модульність

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

Модульність - це властивість системи, що була розкладена на внутрішньо зв'язані, але слабко пов'язані між собою модулі.

Таким чином, принципи абстрагування, інкапсуляції і модульності є взаємодоповнюючими. Об'єкт логічно визначає границі визначеної абстракції, а інкапсуляція і модульність роблять їх фізично непорушними.

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

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

Ієрархія

Що таке ієрархія? Абстракція - річ корисна, але завжди, крім найпростіших ситуацій, число абстракцій у системі набагато перевищує наші розумові можливості. Інкапсуляція дозволяє в якомусь ступені усунути цю перешкоду, забравши з полючи зору внутрішній зміст абстракцій. Модульність також спрощує задачу, поєднуючи логічно зв'язані абстракції в групи. Але цього виявляється недостатньо.

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

Ієрархія - це упорядкування абстракцій, розташування їх по рівнях.

Основними видами ієрархічних структур стосовно до складних систем є структура класів (ієрархія "is-a") і структура об'єктів (ієрархія "part of").

Приклади ієрархії: одиночне спадкування. Важливим елементом об’єктно-орієнтованих систем і основним видом ієрархії "is-a" є згадувана вище концепція спадкування. Спадкування означає таке відношення між класами (відношення батько/нащадок), коли один клас запозичає структурну чи функціональну частину одного чи декількох інших класів (відповідно, одиночне і множинне спадкування). Іншими словами, спадкування створює таку ієрархію абстракцій, у якій підкласи успадковують будівлю від одного чи декількох суперкласів. Часто підклас добудовує чи переписує компоненти вищестоящого класу.

Семантично, спадкування описує відношення типу "is-a". Наприклад, ведмідь є ссавець, будинок є нерухомість і "швидке сортування" є алгоритм, що сортує. Таким чином, спадкування породжує ієрархію "узагальнення-спеціалізація", у якій підклас являє собою спеціалізований окремий випадок свого суперкласу.

Типізація

Типізація - це спосіб захиститися від використання об'єктів одного класу замість іншого, чи принаймні керувати таким використанням.

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

Ідея узгодження типів займає в понятті типізації центральне місце. Наприклад, візьмемо фізичні одиниці виміру . Поділяючи відстань на час, ми очікуємо одержати швидкість, а не вагу. У множенні температури на силу змісту нєма, а в множенні відстані на силу - є. Усе це приклади сильної типізації, коли прикладна область накладає правила й обмеження на використання і сполучення абстракцій.

 

 





©2015 studopedya.ru Все права принадлежат авторам размещенных материалов.