|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Термінологія ООП
Відправною
крапкою у всій термінології ООП є поняття класу. Класом називається
шаблон, по якому створюються об'єкти.
Кожен об'єкт, створений на основі класу, називається екземпляром цього
класу. Методи, властивості і процедури подій, визначені усередині класу,
називаються членами. Припустимо, ви пишете програму для роботи з інформацією
про співробітників компанії. Поза сумнівом, в такій програмі буде визначений
клас Employee; кожен екземпляр класу Employee відповідатиме конкретній
людині. Члени класу Employee повинні відповідати специфіці вирішуваних завдань
(наприклад, у властивості Name зберігатиметься ім'я працівника, а метод Raise-salary використовуватиметься
для підвищення зарплати).
Стосунки між класами в програмах
У традиційному ООП передбачено три типи стосунків між класами:
Повернемося до класичної трійки. Відношення використання, найочевидніше і поширеніше,
всього лише означає, що один клас залежить від іншого. У всіх ситуаціях, коли
один об'єкт посилає повідомлення іншого об'єкту, можна говорити про залежність
між цими об'єктами. У узагальненому випадку клас А використовує клас Би, якщо:
або
Термін «включення»
(агрегація) означає, що об'єкт класу А містить внутрішні об'єкти класу
Б. На базі включення реалізується
методика делегування, коли поставлене перед зовнішнім об'єктом
завдання передоручається внутрішньому об'єкту, що спеціалізується на вирішенні
завдань такого роду. Агрегація з делегуванням методів була дуже поширеним
явищем в колишніх версіях VB, оскільки цей
принцип використовувався
при створенні нових елементів (пригадаєте, як створювалися нові, спеціалізовані
текстові поля — ви розміщували текстове іоле усередині форми призначеного
для користувача елементу, а потім запускали программу-мастер, яка
автоматично генерувала код делегування). Агрегація як і раніше
широко використовується в VB .NET, але в багатьох ситуаціях йому на зміну приходить
спадкоємство — третій тип стосунків між класами. Спадкоємство вважається за
один з чотирьох «наріжних каменів» ООП разом з абстракцією,
інкапсуляцією і поліморфізмом. Всі чотири концепції будуть розглянуті в найближчих
чотирьох розділах.
Абстракцією називається
моделювання об'єктів в програмі. Іншими словами, мова йде про
імітації реально існуючих об'єктів, що відображає особливості їх взаємодії
на навколишньому світі. Так, перша об'єктно-орієнтована мова Simula (http://java.sun.com/people/jag/SimulaHistory.html)
розроблявся спеціально для завдань імітації і моделювання. Втім, модні
концепції віртуальної реальності виводять принцип абстракції на абсолютно новий
рівень, не пов'язаний з фізичними об'єктами. Абстракція необхідна, тому
що успішне використання ООП можливе лише в тому випадку, якщо ви зможете
виділити змістовні аспекти своєї проблеми. Приступаючи
до побудови об'єктної моделі, завжди ставте собі питання: які властивості
і методи повинні входити в об'єкт, щоб він адекватно моделював ситуацію для
вирішення поставленого завдання?
У ООП термін «інкапсуляція»
означає те, що ми зазвичай називаємо маскуванням даних.
Приховуючи дані, ви визначаєте властивості і методи для роботи з ними. Пригадаєте,
що мовилося вище, — успішне застосування ООП можливе лише в тому випадку,
якщо всі операції з внутрішніми даними об'єкту здійснюються за допомогою
обміну повідомленнями. Дані об'єкту зберігаються в полях екземпляра; також
часто зустрічається термін «змінні екземпляра». По суті,
це одне і те ж, і вибір залежить в основному від того, до якого терміну ви звикли;
у цій книзі зазвичай використовується термін «поля екземпляра». Поточний
стан об'єкту визначається поточними значеннями полів екземпляра. Не забувайте
головне правило: ніколи не надайте прямий доступ ззовні до полів екземпляра
(внутрішнім даним об'єкту).
Повернемося наприклад з об'єктно-орієнтованою програмою для відділу кадрів, в якій
ми визначили клас Employee. У змінних класу Еmplоуєе можуть зберігатися наступні
відомості:
Щоб змінити значення полів екземпляра, користувачі не звертаються до них безпосередньо,
а змінюють властивості і викликають методи типу Rai sesalаrу. Зрозуміло,
метод Raisesalary змінюватиме поле з поточною зарплатою, але в нетривіальному класі
Employee він може працювати з декількома полями. Наприклад, легко уявити собі
метод Rai sesalагу, який ухвалює рішення про підвищення зарплати з урахуванням її
поточного рівня, робочого стажу і особистих досягнень працівника. Підведемо підсумок.
Інкапсуляція визначає функціональність об'єкту з погляду користувача. Її безпосередніми
проявами в VB .NETвыступают члени класу (методи, події і властивості).
Як
приклад спадкоємство уявіть собі класи для окремих категорій працівників
(клас Programmer, клас Manager і т. д.). Механізм, використовуваний для створення
таких класів на базі класу Empl oyee, називається спадкоємством. У ієрархії
спадкоємства клас Employee називається базовим, а клас Programmer —
похідним класом. Похідні класи:
Наприклад,
метод Raisesalary класу Manager може давати менеджерові велику надбавку до платні,
чим метод Raisesalary класу Programmer, при однаковому стажі і особистих показниках. Похідний клас
може містити нові методи, що не мають аналогів в базовому класі. Наприклад,
в клас Manager може бути включене нова властивість Secretary. Розробники давно хотіли
бачити спадкоємство в VB і голосно скаржилися на його відсутність. Не можна
сказати, що шум був піднятий на порожньому місці, проте багато хто схильний переоцінювати
важливість спадкоємства. Річ у тому, що спадкоємство, якщо гарненько розібратися,
всього лише позбавляє програміста від необхідності наново писати готовий код.
У спадкоємстві немає ніякої містики — це лише спосіб спростити повторне використання
програмної коди. У нашому прикладі класи Employee і Manager володіли рядом
схожих рис (наявність дати найму, зарплати і т. д.). Навіщо програмувати властивість
Salary в двох місцях, якщо код буде абсолютно однаковим? При повноцінній реалізації
спадкоємства використання функціональності базового класу в похідному класі
практично не вимагає додаткових зусиль — похідний клас спочатку
успадковує всі члени свого предка. Програміст може перевизначити деякі
члени базового класу відповідно до специфіки похідного класу. Наприклад, якщо
менеджер автоматично отримує 8-процентну надбавку до зарплати, тоді як
для більшості працівників надбавка складає всього 4%, метод Raisesalагу класу
Manager повинен замінити метод Raisesalary базового класу Employee. З іншого
боку, методи ніби Getname в зміні не мають потреби і залишаються в колишньому
вигляді. Наприкінці ми хочемо попередити:
не використовуйте спадкоємство, якщо ви твердо не упевнені в існуванні логічного
зв'язку «є окремим випадком». Наприклад, не створюйте клас
Contractor (позаштатний працівник), похідний від Employee, тільки для того,
щоб позбавитися від клопоту по дублюванню коди властивостей імені або номера соціального
страхування. Позаштатний працівник не є таким, що служить компанії,
і бухгалтер, простоти ради що оформив його по загальних правилах, тільки
наживе собі неприємності з податковою інспекцією. То ж відноситься і до вас: застосування
спадкоємства за відсутності логічного зв'язку «є окремим випадком»
приведе до сумних наслідків (див. розділ 5).
У традиційному трактуванні термін «поліморфізм»
(від грецького «багато форм») означає, що об'єкти похідних
класів вибирають використовувану версію методу залежно від свого положення в ієрархії
спадкоємства. Наприклад, і в базовому класі Employee, і в похідному класі Manager
присутній метод для підвищення зарплати працівника. Проте метод Raisesalаrу для об'єктів
класу Manager працює не так, як однойменний метод базового об'єкту Employee. Класичний
прояв поліморфізму при роботі з класом Manager, похідним від Empl oyee,
полягає в тому, що при виклику методу по посиланню на Empl oyee буде автоматично
вибрана потрібна версія методу (базового або похідного класу). Допустимо, в
програмі метод Raisesalary викликається по посиланню на Employee.
У обох
випадках об'єкт вибирає метод залежно від отриманого повідомлення. При відправці повідомлення
не потрібно знати, до якого класу фактично принадлежіт
об'єкт; досить розіслати повідомлення всіх об'єктів Employee і доручити вибір
поліморфного методу компілятору. Наступний приклад показує, чому
поліморфізму надається таке велике значення. Одному з авторів доводилося
консультувати компанію, що займалася комп'ютерною обробкою медичних аналізів.
Кожного разу, коли в процес тестування включався новий реактив, програмістам
доводилося переглядати багато тисяч рядків коди, шукати команди Select
Case і додавати в них секції Case для нового реактиву. Варто було пропустити
хоч би одну... і нам би не хотілося, щоб цей реактив випробовувався на
наших аналізах крові. Звичайно, виправлення багатьох команд Select Case перетворював супровід
в справжній кошмар, що вимагає довгого годинника тестування. Поліморфізм дозволяє
написати програму, яка в подібній ситуації обмежується єдиною зміною.
Все, що від вас буде потрібно, — визначити для нового реактиву новий
клас і правильно запрограмувати в нім перевизначувані або додані
методи. Чому? Тому
що в головній програмі можна буде використовувати конструкції наступного вигляду: For Each
reagent in Reagents reagent.Method Next
Показаний цикл автоматично працюватиме з новим реактивом, а необхідність в довгих
пошуках Sel ect Case відпаде. Select
Case reagent Case iodine ' Дії з
йодом Case benzene ' Дії з бензолом ' І так далі для
100 різних випадків в 100 місцях У приведеному
вище фрагменті цикл For Each перебирає всі можливі реактиви, і завдяки
чарівній властивості поліморфізму компілятор знайде метод, який повинен
викликатися для кожного конкретного реактиву. Правильне використання поліморфізму
позбавить вас від громіздких команд Select Case, що вибирають потрібну дію залежно
від типу об'єкту.
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||