загрузка...
загрузка...
На головну

інтерфейсні класи

  1. Біржовий товар, класи і характеристики біржового товару
  2. У ООП базовими одиницями програм і даних є класи.
  3. Найважливіші класи органічних сполук
  4. Глава 11. НАЙВАЖЛИВІШІ КЛАСИ НЕОРГАНІЧНИХ СОЕДИНЕНИЙ
  5. Глава VI. громадські класи
  6. Горизонталь - класи зірок, вертикаль - світність зірок
  7. Д 7.0 8,0 9,0 10,0 11,0 12.0 КЛАСИ ЗА КІЛЬКІСТЮ ЛЕЙКОЦИТІВ (тис.)

Концепція інтерфейсів - одна з центральних в сучасних реалізаціях об'єктних мов, хоча до «класичним» концепціям об'єктної технології вона не відноситься. Поняття інтерфейсних класів (ІК) вперше було введено в широку практику в мові Java і швидко завоювало популярність. У Delphi Pascal цей механізм з'явився, починаючи з версії 4.0. Дуже активно інтерфейси використовуються в Java 2 і MS .NET. У стандартному С ++ в чистому вигляді цього механізму немає, але він є, наприклад, в реалізації мови для платформи .NET.

Інтерфейсний клас - це повністю абстрактний клас,тобто все його методи є абстрактними і представлені в класі тільки своїми заголовками. Інтерфейсні класи вводяться не для створення об'єктів-екземплярів, а для конструювання «робочих» класів, визначаючи протокол взаємодії клієнтів з цими класами.

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

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

В результаті об'єктна модель розроблювальної програмної системи може містити такі різновиди класів:

· інтерфейсні класи, які декларують (але не реалізують!) деякий поведінку, яке повинні підтримувати робочі класи; інтерфейсні класи містять тільки заголовки методів і загальні незмінні властивості-константи і можуть наслідувати відразу від декількох інтерфейсів (і тільки інтерфейсів!).

· абстрактні класи, побудовані на основі одного батьківського класу і декількох інтерфейсних класів; абстрактні класи можуть містити змінні властивості і програмний код деяких методів, але основне призначення абстрактних класів - створення в ієрархії класів деякої спільності властивостей і методів, успадкованих дочірніми «робочими» класами.

· «робочі»Класи, створені на основі одного з батьків і які застосовують (реалізують) всі заявлені інтерфейси; всі методи повинні мати програмну реалізацію, і саме ці класи є основою створення екземплярів-об'єктів.

Схематично взаємодія цих класів можна показати наступним чином.


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

 
 


За допомогою інтерфейсів це завдання можна реалізувати наступним чином.

Етап 1. Створюються три інтерфейсних класу:

· Інтерфейс IPerson вводить заголовки методів, що визначають загальнолюдське поведінку персоналій навчального закладу, таке як обробка особистих даних (наприклад, прізвища, адреси, дати народження і т.д.).

· Інтерфейс IStudent успадковує протокол поведінки, заявлений в класі Iperson, і доповнює його специфічною поведінкою студентів (наприклад, обробкою навчальних даних студента, оплатою навчання та ін.).

· Інтерфейс ISotr також успадковує протокол поведінки, заявлений в класі IPerson, але доповнює його поведінкою, характерною вже для співробітників (наприклад, нарахування зарплати, облік відпрацьованого часу і т.д.).

Етап 2. Створюються такі чотири класи:

· Абстрактний клас Person вводить необхідні персональні властивості і реалізує інтерфейс Iperson.

· Клас Student успадковує клас Person, вводить необхідні властивості для зберігання студентських даних і реалізує інтерфейс Istudent.

· Клас Sotr успадковує клас Person, вводить необхідні властивості для зберігання даних співробітників і реалізує інтерфейс Isotr.

· Клас StudSotr успадковує клас Person, вводить необхідні властивості для зберігання навчальних і робочих даних і реалізує ДВА інтерфейсу - IStudent і Isotr.

У цій схемі важливо відзначити, що реалізація інтерфейсу в класі вимагає від класу лише забезпечення зазначеного списку методів, але дає можливість в різних класах, що реалізують один і той же інтерфейс, по різному виконувати програмну реалізацію методів інтерфейсу! Наприклад, розрахунок зарплати і організація оплати за навчання в класі StudSotr може відрізнятися від аналогічних методів в класах Student і Sotr.

Схематично взаємодія зазначених класів представлено на наступному малюнку.

 
 


Для опису всіх цих класів на мові Java необхідно зробити наступні оголошення (для наочності наводяться тільки деякі властивості і методи):

interface IPerson

{ void SetFam (string aFam);

string GetFam ();

}

interface IStudent extends IPerson

{ void SetOplata (); // Заголовок методу розрахунку оплати за навчання

int GetOplata ();

}

interface ISotr extends IPerson

{ void SetZarplata (); // Заголовок методу розрахунку зарплати

int GetZarplata ();

}

class Person implements IPerson

{ private string Fam;

public void SetFam (string aFam) {Fam = aFam;}

public string GetFam () {return Fam;}

}

class Student extends Person implements IStudent

{private int Oplata; // Властивість - сума оплати за навчання

public void SetOplata (); {Код для звичайних студентів}

public int GetOplata () {return Oplata;}

};

class Sotr extends Person implements ISotr

{private int Zarplata; // Властивість - зарплата співробітника

public void SetZarplata () {код для звичайних співробітників}

public int GetZarplata () {return Zarplata;}

};

class StudSotr extends Person implements IStudent, ISotr

{ private int Oplata;

private int Zarplata;

public void SetOplata () {код для студентів-співробітників}

public int GetOplata () {return Oplata;}

public void SetZarplata () {код для співробітників-студентів}

public int GetZarplata () {return Zarplata;}

}

Коментарі до зроблених оголошенням:

1. Інтерфейсні класи оголошуються за допомогою директиви interface.

2. При спадкуванні інтерфейсів використовується та ж директива extends,що і для звичайних класів.

3. При описі інтерфейсів ніякі директиви обмеження доступу можна не використовувати, тому що автоматично всі методи інтерфейсних класів вважаються відкритими (public).

4. При описі класу для вказівки реалізовуються в класі інтерфейсів використовується директива implements.

Як було зазначено вище, об'єкти інтерфейсних класів не створюються, але можна оголошувати і використовувати змінні інтерфейсних класів. Це особливо важливо при оголошенні формальних параметрів методів. Зокрема, можна оголосити метод з формальним параметром типу IPerson:

SomeMethod (IPerson aPar);

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

SomeMethod (aStud); SomeMethod (aSotr); SomeMethod (aStudSotr);

Цей механізм дуже широко використовується в стандартних бібліотеках класів, зокрема, при реалізації колекцій-контейнерів, до розгляду яких тепер вже можна підійти впритул. Розглянемо організацію класів-колекцій в мові Java 2, зазначивши, що дуже схоже колекції реалізовані в бібліотеці .NET Framework.

Перш за все, необхідно дати короткий опис набору інтерфейсів, використовуваних в контейнерної бібліотеці Java 2.

базовий інтерфейс Collection вводить найбільш загальний набір методів обробки послідовностей елементів (об'єктних покажчиків типу Object) - додавання одного або цілої групи елементів, видалення одного або всіх елементів, перевірка наявності елемента і порожнечі контейнера, запит поточного числа елементів в контейнері. Цей інтерфейс не реалізується «робочими» контейнерами, а служить лише основою для створення більш функціональних інтерфейсів.

нащадками інтерфейсу Collection є інтерфейси List и Set. Перший з них додає методи для індексування елементів послідовності: додавання елемента по його індексу зі зрушенням хвостовій частині, запит елемента по його індексу, запит індексу першого або останнього появи заданого елемента, заміна елемента в заданій позиції. Індексація елементів починається з нуля. Саме на основі інтерфейсу List створюються дуже популярні класи-контейнери ArrayList и LinkedList.

інтерфейс Set визначає невпорядкований набір неповторюваних елементів. Нові методи в цьому інтерфейсі не повинні додаватися, просто на метод додавання покладається обов'язок перевіряти наявність елемента в наборі. На основі інтерфейсу Set створюється клас HashSet і інтерфейс SortedSet.Останній призначений для створення впорядкованих множин, елементи в якому відсортовані або природним чином, або за допомогою спеціального інтерфейсу Comparartor. На основі інтерфейсу SortedSet створюється клас TreeSet.

 Фрагмент ієрархії контейнерів для даної групи колекцій представлений на наступною схемою:


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

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

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

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

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

Другу групу контейнерів складають так звані таблиці (map), або словники, або асоціативні масиви як набори пар «ключ-значення». Пошук значення проводиться по ключу. І ключ, і значення є об'єктами самого загального типу Object. Основу цієї групи складають два інтерфейси - базовий інтерфейс Map і його нащадок SortedMap.

Окремого обговорення заслуговують додаткові інтерфейси, необхідні для реалізації алгоритмів обробки колекцій. Як відомо, дві основні задачі обробки будь-яких наборів даних - це пошук і сортування. Для їх реалізації треба вміти організовувати циклічний прохід по набору і порівняння елементів набору. З цією метою в базову бібліотеку класів введені інтерфейси Iterator, ListIterator и Comparator.

В інтерфейсі Iterator оголошені два основні методи:

· метод hasNext() Повертає true, якщо в колекції ще є елементи;

· метод next() Виконує перехід до наступного елементу колекції і повертає поліморфний покажчик на нього.

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

ArrayList MyArrList = new ArrayList (); // Створення контейнера

MyArrList.Add ( «first item»); // Додавання трьох рядків

MyArrList.Add ( «second item»);

MyArrList.Add ( «third item»);

Iterator MyIter = MyArrList.iterator (); // Створення ітератора

while (MyIter.hasNext ()) System.out.println (MyIter.next ()); // вивід

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

інтерфейс ListIterator розширює інтерфейс Iterator і є більш функціональним, оскільки дозволяє не тільки проходити колекцію в прямому або зворотному напрямку, а й виконувати операції додавання, видалення або заміни елементів. У цей інтерфейс додані наступні методи:

· hasPrevious() Перевіряє наявність попереднього елемента;

· previous() Виконує перехід до попереднього елемента і повертає об'єктний покажчик на нього;

· add (Object item) додає елемент-об'єкт перед поточним елементом

· nextindex() Повертає індекс поточного елемента;

· previousindex() Повертає індекс попереднього елемента;

· set (Object item) замінює поточний елемент на елемент item.

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

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

1. Оголошення класу, застосовує інтерфейс Comparator і містить необхідну реалізацію методу compare:

class NewCompare implements Comparator

{ public int compare (Object aObj1, Object aObj2)

{Реалізація порівняння вхідних об'єктів}

};

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

TreeSet MyTree = new TreeSet (new NewCompare ());

3. Заповнення контейнера в тому порядку, який визначений заданим компаратором.

Ще одним цікавим моментом стандартної бібліотеки контейнерів мови Java є наявність в ній класу Collections, що містить програмну реалізацію основних алгоритмів обробки даних. Ці алгоритми реалізовані як методи класу (директива static), Що дозволяє звертатися до них без створення об'єктів даного класу, а використовуючи лише ім'я класу і ім'я методу. Алгоритми реалізують такі основні операції: пошук мінімального або максимального елемента в колекції, копіювання елементів однієї колекції до іншої, двійковий пошук заданого елемента, випадкове перемішування колекції, сортування елементів (в тому числі за допомогою заданого компаратора). Деякі автори відзначають, що на створення бібліотеки контейнерів мови Java велике ідеологічне вплив справила концепція узагальнених функцій, реалізована найбільш повно в мові С ++ у вигляді так званих шаблонів. Дана концепція коротко розглядається в наступному розділі посібника.

А на завершення даного розділу відзначимо, що оголошення та використання інтерфейсних класів в Delphi Pascal виглядає наступним чином:

type ISotr = interface (IHuman) // оголошення інтерфейсу

заголовки методів;

end;

TStudSotr = class (THuman, IStud, ISotr) // реальний клас

оголошення властивостей;

заголовки методів інтерфейсу IStud;

заголовки методів інтерфейсу ISotr;

заголовки власних методів;

end;

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

 




Приклади тестових завдань | Основні типи взаємодії | Агрегація і композиція | Узагальнення і спадкування | Порядок виконання роботи; | Приклади тестових завдань | Перевизначення методів. Поліморфні (віртуальні) методи | Поліморфні об'єктні покажчики | Контейнери та їх об'єктна реалізація | практичні завдання |

загрузка...
© um.co.ua - учбові матеріали та реферати