Ноу Інти, лекція, відносини між класами
Анотація: Класи. Відносини між класами. Ставлення клієнти - постачальники. Ставлення успадкування. Одиничне успадкування. Батьки і спадкоємці. Предки і нащадки. Що успадковують нащадки. Що можуть змінити нащадки. Одностороннє присвоювання. Контроль типів і зв'язування - статична і динамічна. Поліморфізм. Проектування класів. Абстрактні класи. Класи поведінки.
Відносини між класами
Кожен клас. як не раз зазначалося, грає дві ролі: він є модулем - архітектурної одиницею, і він має змістовний сенс, визначаючи певний тип даних. Але класи програмної системи - це ансамбль, в якому класи, граючи свої ролі, не є незалежними - всі вони знаходяться в певних відносинах один з одним. Два основних типи відносин між класами визначені в ОО-системах. Перше ставлення "клієнти і постачальники". називається часто клієнтським ставленням або відношенням вкладеності (вбудовування). Друге відношення "батьки і спадкоємці" називається відношенням успадкування.
Визначення 1. Класи А і В знаходяться у відношенні "клієнт-постачальник", якщо одним з полів класу В є об'єкт класу А. Клас А називається постачальником класу В. клас В називається клієнтом класу А.
Обидва відносини - успадкування і вкладеності - є транзитивними. Якщо В - клієнт А. а З - клієнт В. то це означає, що С - клієнт А. Якщо В - спадкоємець А. а З - спадкоємець В. то це означає, що С - спадкоємець А.
Визначення 1 і 2 задають прямих або безпосередніх клієнтів і постачальників, прямих батьків і спадкоємців. Внаслідок транзитивності необхідно ввести поняття рівня. Прямі клієнти і постачальники, прямі батьки і спадкоємці відносяться до відповідного рівня 1 (клієнти рівня 1, постачальники рівня 1 і так далі). Потім слід рекурсивне визначення. прямий клієнт клієнта рівня k відноситься до рівня k + 1.
Для відносини спадкування використовується термінологія, запозичена з природної мови. Прямі класи-спадкоємці часто називаються синівським або дочірніми класами. Непрямі батьки називаються предками, а їх непрямі спадкоємці - нащадками.
Зауважу, що ланцюжки вкладеності і успадкування можуть бути досить довгими. На практиці цілком можуть зустрічатися ланцюжка довжини 10. Наприклад, бібліотечні класи, складові систему Microsoft Office, повністю побудовані на відносно вкладеності. При програмній роботі з об'єктами Word можна почати з об'єкта, що задає додаток Word. і дістатися до об'єкта, що задає окремий символ в деякому слові деякого пропозиції одного з відкритих документів Word. Для вибору потрібного об'єкту можна задати такий ланцюжок: додаток Word - колекція документів - документ - область документа - колекція абзаців - абзац - колекція пропозицій - пропозиція - колекція слів - слово - колекція символів - символ. У цьому ланцюжку кожному поняттю відповідає клас бібліотеки Microsoft Office, де кожна пара сусідніх класів пов'язана відношенням "постачальник-клієнт".
Класи бібліотеки FCL пов'язані як ставленням вкладеності. так і ставленням спадкування. Довгі ланцюжки успадкування досить характерні для класів цієї бібліотеки.
Відносини "є" і "має"
При проектуванні класів часто виникає питання, яке ж відношення між класами потрібно побудувати. Розглянемо зовсім простий приклад двох класів - Square і Rectangle. описують квадрати і прямокутники. Напевно, зрозуміло, що ці класи слід пов'язати швидше ставленням спадкування. ніж вкладеності; менш зрозумілим залишається питання, а який з цих двох класів слід зробити батьківським. Ще один приклад двох класів - Car і Person. описують автомобіль і персону. Якими відносинами з цими класами повинен бути пов'язаний клас Person_of_Car. описує власника машини? Чи може він бути спадкоємцем обох класів? Знайти правильні відповіді на ці питання проектування класів допомагає розуміння того, що ставлення "клієнт-постачальник" задає відношення "має" ( "has"). а відношення успадкування задає відношення "є" ( "is a"). У разі класів Square і Rectangle зрозуміло, що кожен об'єкт квадрат "є" прямокутником, тому між цими класами має місце відношення успадкування. і батьківським класом є клас Rectangle. а клас Square є його нащадком.
У разі автомобілів, персон і власників авто також зрозуміло, що власник "має" автомобіль і "є" персоною. Тому клас Person_of_Car є клієнтом класу Car та спадкоємцем класу Person.
ставлення вкладеності
Розглянемо два класи A і B. пов'язаних ставленням вкладеності. Обидва класи застосовуються для демонстрації ідей і тому влаштовані просто, не несучи особливого смислового навантаження. Нехай клас-постачальник A вже побудований. У класу два поля, конструктор, один статичний і один динамічний метод. Ось його текст:
Побудуємо тепер клас B - клієнта класу A. Клас буде влаштований схожим чином, але на додаток матиме одним зі своїх полів об'єкт inner класу A:
Зверніть увагу: конструктор клієнта (класу B) відповідає за ініціалізацію полів класу, тому він повинен створити об'єкт постачальника (класу A), викликаючи, як правило, конструктор постачальника. Якщо для створення об'єктів постачальника потрібні аргументи, то вони повинні передаватися конструктору клієнта, як це зроблено в нашому прикладі.
Після того як конструктор створив поле - об'єкт постачальника - методи класу можуть використовувати цей об'єкт, викликаючи доступні клієнту методи і поля класу постачальника. Метод класу B - MethodB1 починає свою роботу з виклику: inner.MethodA. використовуючи сервіс, що поставляється методом класу A.