|
|||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||
|
Інтерфейси
Ймовірно,
ви переконалися в тому, що спадкоємство займає важливе місце в VB .NET, але для
повноцінного використання об'єктно-орієнтованих засобів VB .NET вам також
доведеться освоїти реалізацію інтерфейсів. Етой важливій темі присвячено декілька
найближчих розділів. Перш за
все реалізацію інтерфейсу можна розглядати як контракт,
обов'язковий для будь-якого класу. Інтерфейси займали найважливіше місце в програмуванні
СОМ, а також в реалізації об'єктно-орієнтованих засобів в колишніх версіях
VB. При реалізації інтерфейсу класс-обязуєтся надавати деяку
функціональність відповідно до сигнатур заголовків членів відтепер
і у віка століть. На відміну від об'єктів при спадкоємстві інтерфейси не зв'язані
ніякими взаємними залежностями — кожна реалізація інтерфейсу існує незалежно
від інших. Реалізація інтерфейсу
припускає, що ваш клас містить методи із строго певними сигнатурами.
Ці методи можуть бути порожніми, але вони обов'язково мають бути
присутніми. Фактична
реалізація методів не фіксується; як було тільки що сказано, методи можуть
взагалі нічого не робити. Підтримка інтерфейсу — всього лише зобов'язання визначити
методи із заданими сигнатурами. З цього простого факту витікає безліч чудових
следствій. Особливий інтерес представляють наступні:
А зараз
подумайте, що відбудеться, якщо:
Відбувається
наступне: у режимі жорсткої перевірки типів (Option Stricton) програма взагалі
не компілюватиметься. Якщо цей режим відключити, розумний компілятор .NET зрозуміє, що
виклик методу класу не вдасться замінити в коді, що відкомпілювався, якоюсь подібністю
простого виклику функції. Таким чином, компілятору доведеться згенерувати значно
більший об'єм коди. Фактично він винен під час виконання програми ввічливо
запитати у об'єкту, чи підтримує він метод з вказаною сигнатурою, і якщо
підтримує — чи не буде він заперечувати проти його виклику? Подібне рішення
володіє двома характерними особливостями, із-за яких воно працює значно
повільніше і набагато частіше приводить до виникнення помилок:
Описаний
процес називається пізнім скріпленням (late binding). Він не тільки значно
поступається ранньому скріпленню за швидкістю, але і взагалі не дозволений при включеному
режимі Option Strict за винятком пізнього скріплення, заснованого на застосуванні
рефлексії.
Механіка
реалізації інтерфейсу
У багатьох компаніях, що
займаються програмуванням (хоч би в Microsoft), існує посада
провідного програміста або провідного фахівця з тестування. Припустимо, ви
вирішили розширити систему обліку кадрів і включити в неї ці нові посади з
особливими властивостями — скажімо, наявністю фонду матеріального заохочення для підлеглих, що
особливо відрізнилися. У описаній
вище ієрархії класів VB .NET визначити новий клас «провідний фахівець»
не вдасться, оскільки класи Programmer і Tester вже є похідними від
класу Empl oyee, а множинне спадкоємство в .NET не підтримується. Перед
нами ідеальний приклад ситуації, коли вам на допомогу приходять інтерфейси. Перш за все
інтерфейс необхідно визначити. На відміну від Vb6, де інтерфейс був звичайним
класом, в VB .NET з'явилося спеціальне ключове слово Interface. Припустимо,
наші «ведучі» повинні оцінювати своїх підлеглих і витрачати засоби
з фонду матеріального заохочення. Визначення інтерфейсу виглядає так: Public
Interface Ilead Sub Spendmoralefund(Byval
amount As Decimal) Function Rate(Byval
aperson As Employee) As String Property Myteam()
As Empl oyee () Property Moralefuod()
As Decimal End Interface Звернете увагу
— у визначенні інтерфейсу відсутні модифікатори рівня доступу Publiс
і Private. Дозволені тільки оголошення Sub, Function і Property з ключовими словами
Overloads і Default. Як бачите, визначення інтерфейсу виглядає просто. Будь-який
клас, що реалізовує інтерфейс Ilead, зобов'язується містити:
Як буде
показано нижче, імена методів реалізації неістотні — головне, щоб методи
мали задану сигнатуру. Щоб реалізувати інтерфейс
в класі, перш за все переконаєтеся в тому, що він сам або посилання на нього
входить в проект. Далі за ім'ям класу і командою Inherits в програму включається
рядок з ключовим словом Implements, за яким слідує ім'я інтерфейсу. Приклад: Public
Class Leadprogrammer Inherits
Programmer Implements Head End Class Ім'я Head підкреслюється
синьою хвилястою межею, що свідчить про виниклу проблему.
Тим самим компілятор наполягає на виконанні зобов'язань по реалізації інтерфейсу
хоч би порожніми методами. Як це зробити?
На відміну від ранніх версій VB, де члени класів, що входять в реалізацію
інтерфейсу, позначалися особливою формою сигнатури, в VB .NET використовується наочніший
синтаксис. У наступному фрагменті відповідний рядок виділений жирним шрифтом. Public Function
Rate(Byval aperson As Employee) As String _ Implements Ilead.Rate
End Function Звичайно, імена
членів інтерфейсу зазвичай збігаються з іменами методів, що їх реалізовують,
але це не обов'язково. Наприклад, наступний фрагмент цілком допустимий. Public Property Ourmoralefund() As Decimal Implements Head.MoraleFund
Get Return m_moral e Fund End Get Set(Byval Value
As Decimal) m_moralefund =Value End Set End Property Головне, щоб
типи параметрів і повертаного значення відповідали сигнатурі даного члена
інтерфейсу. При оголошенні методу можуть використовуватися будь-які допустимі модифікатори,
що не заважають виконанню контракту, — Overloads, Overrides, Overridable,
Public, Private, Protected, Friend, Protected Friend, Mustoverride, Default
і Static. Забороняється тільки використовувати атрибут Shared, оскільки члени інтерфейсу
повинні належати конкретному екземпляру, а не класу в цілому. Якщо в реалізації
інтерфейсу використовується член класу з модифікатором Pri vate, звернення до цього
члена можливі тільки через змінну, оголошену з типом даного інтерфейсу.
На відміну від попередніх версій VB в решті випадків до членів інтерфейсу завжди
можна звертатися через об'єкти класу. Тепер вам не доведеться привласнювати їх
проміжним інтерфейсним змінним. Приклад: Dim tom As New
Leadprogrammer("Tom",65000) tom.SpendMoraleFund(500) Проте в зворотних
перетвореннях доводиться використовувати функцію Стуре: Dim tom As New
Leadprogrammer("Tom". 65000) Dim alead As
Ilead.aName As String alead =
tom aname = Ctype(alead.
Programmer).TheName 'OK Наступний рядок
недопустимий: aname =tom.TheName
' ЗАБОРОНЕНО! Нижче перераховані загальні
правила перетворення між типом об'єкту і інтерфейсом, ним що реалізовується.
Щоб визначити,
чи реалізує об'єкт деякий інтерфейс, скористайтеся ключовим словом Typeof
у поєднанні з Is. Приклад: Dim torn As New Leadprogrammer("tom". 50000) Console.WriteLine((Typeof
(tom) Is Head)) Другий рядок
виводить значення True. Один метод
може реалізовувати декілька функцій, визначених в одному інтерфейсі: Public Sub itsok Implements Interface1.Ml.Interfacel.M2,Interfacel.M3 Нижче приведена
повна версія класу Leadprogrammer. Звичайно, реалізація методів інтерфейсу
виглядає декілька умовно, проте обпадає уявлення про те, що можна зробити
при реалізації інтерфейсу: Public Class Leadprogrammer Inherits Programmer Implements Head Private m_moralefund As Decimal Private m_myteam
As Employee() Public Function Rate(Byval aperson As Employee) As String _ Implements Head.Rate Return aperson.TheName & "rating to be done" End
Function Public Property Myteam() As Employee() Implements Ilead.MyTeam Get Return
m_myteam End
Get Seubyval Value As Employee()) X. m_myteam
= Value End Set
End Property Public Sub Spendmoralefund(Byval amount As Decimal)_ Implements Ilead.SpendMocaleFund ' Витратити
засоби з фонду мат. заохочення Console.WriteLine("Spent " & amount.ToString()) End Sub Public Property Ourmoralefund()As Decimal Implements Ilead.MoraleFund Get Return
m_moralefund End
Get Settbyval Value
As Decimal) m_moralefund = Value End Set End Property Public Sub New(Byval
thename As String. Byval cursalary As Decimal) Mybase.New(thename. cursalary) End Sub End Class
|
|
|||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||