:: Меню ::

Головна
  • Про сайт
  • Введення
  • Середовище програмування VB .NET: Visual Studio .NET
  • Вирази, оператори і передача управління
  • Класи і об'єкти
  •  Спадкоємство і інтерфейси
  • Обробка подій і делегати
  • Обробка помилок в VB .NET
  • Форми Windows, графічний вивід і друк
  • Уведення-виведення
  •  Багатопотокові застосування
  • Підтримка баз-даних в VB .NET
  • Короткий огляд ASP .NET
  • Складки .NET, установка додатків і COM Interop
  • Книга для гостей
    Контакти
    Добавити у вибране

    :: Друзі ::

     
     

    :: Лічильники ::

    = =

     

     

     

     

    Нетривіальне застосування інтерфейсів

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

    Public Interface Ileadprogrammer

    Inherits Head

    Public Function Upgradehardware(aperson As Programmer)

    End Interface

    В цьому випадку реалізація Ileadprogrammer вимагає додаткового виконання контракту інтерфейсу Head.

    На відміну від класів, які можуть успадковувати лише від одного базового класу, інтерфейс може бути оголошений похідним від декількох інтерфейсів:

    Public Interface Ileadprogrammer

    Inherits Head.Inherits Icodeguru

    Public Function Upgradehardware(aperson As Programmer)

    End Interface

    Оскільки інтерфейс може успадковувати від декількох інтерфейсів, реальна ситуація, при якій в нім потрібно буде визначити два однойменні методи, що належать до різних інтерфейсів, — наприклад, якщо інтерфейси Head і Icodeguru містять методи з ім'ям Spendmoralefund. В цьому випадку ви не зможете звернутися до одного з цих методів через змінну типу, що реалізовує такий інтерфейс:

    Dim tom As New Leadprogrammer("Tom", 65000)

    tom.SpendMoraleFund(500)

    Інтерфейс повинен указуватися явно, як в наступному фрагменті:

    Dim tom As New Leadprogrammer("Tom", 65000)

    Dim acodeguru As Icodeguru

    acodeguru = tom

    acodeguru.SpendMoraleFund(500)

    Вибір між інтерфейсами і спадкоємством

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

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

    Найважливіші інтерфейси .NET Framework

    Описати всі інтерфейси .NET Framework на декількох сторінках неможливо, але хоч би отримати деяке уявлення про них цілком реально. Інтерфейси Icloneable і Idisposable володіють особливою декларативною функцією — реалізовуючи їх, ви тим самим заявляєте, що ваш клас володіє якійсь стандартною функціональністю, присутньою в багатьох класах.

    • Icloneable: у класі реалізується метод Clone, що забезпечує глибоке копіювання.
    • Idisposable: клас споживає ресурси, які не можуть автоматично звільнятися складальником сміття.

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

    реалізація циклів For-each в Vb6, вони стануть для вас справжнім подарунком!

    Icloneable

    Як було показано в розділі «Memberwiseclone», клонування об'єкту, що містить внутрішні об'єкти, викликає немало проблем. Розробники .NET дають вам можливість повідомити про те, що дана можливість реалізована у вашому класі. Для цієї мети використовується декларативний інтерфейс Icloneable, що складається з єдиної функції Clone:

    Public Interface Icloneable

    Function Clone() As Object

    End Interface

    Цей інтерфейс (а отже, і метод Clone) реалізується в тому випадку, якщо ви хочете надати користувачам свого класу засобу для клонування екземплярів. Далі ви самі вибираєте фактичну реалізацію методу Clone — не виключено, що вона зводитиметься до простого виклику Memberwiseclone. Як було сказано вище, Memberwisecl one нормально клонує екземпляри, поля яких відносяться до структурного типу або є незмінними (такі, як String). Наприклад, в класі Empl oyee клонування екземплярів може здійснюватися методом Clone, оскільки всіма полями є або рядки, або значення структурних типів. Таким чином, реалізація Ic1 опеаи е,для класу Empl oyee може виглядати так:

    Public Class Employee Implements Icloneable

    Public Function Clone() As Object _

    Implements Icloneable.Clone

    Return Ctype(Me.MemberwiseClone, Employee)

    End Function ' І так далі

    End Class

    У класах, що містять внутрішні об'єкти, реалізація методу Clone зажадає значно великих зусиль (хоча в розділі 9 описаний прийом, що дозволяє досить просто вирішити цю задачу в більшості випадків). Так, в приведеному вище класі Embeddedobject необхідно клонувати внутрішній масив, не обмежуючись простим копіюванням.

    Як це зробити? Дуже просто. Оскільки клас Array реалізує інтерфейс Icloneable, він повинен містити метод для клонування масивів. Залишається лише викликати цей метод в потрібному місці. Нижче приведена версія класу Ет-beddedobjects з реалізацією Icloneabl e (ключові рядки виділені жирним шрифтом):

    Public Class Embeddedobjects Implements

    Icloneable Private m_ma() As String

    Public Sub New(Byval anarray() As String)

    m_data = anarray

    End Sub

    Public Function Clone() As Object Implements

    Icloneable.Clone

    Dim temp()As String

    temp = m_data.Clone ' Клонувати масив

    Return New Embeddedobjects(temp)

    End Function

    Public Sub Displaydata()

    Dim temp As String

    For Each temp In m_data

    Console.WriteLine(temp)

    Next End

    Sub Public

    Sub Changedatacbyval

    newdata As String)

    m_data(0) = newdata

    End Sub

    End Class

    Список класів .NET Framework, що реалізовують інтерфейс Шопеаиє (а отже, що підтримують метод Clone), приведений в описі інтерфейсу Шопеаиє в електронній документації.

    Idisposable

    Вище вже згадувалося про те, що метод Finalize не забезпечує надійного звільнення ресурсів, що не знаходяться під управлінням складальника сміття. У програмуванні .NET у цього завдання існує загальноприйняте рішення — клас реалізує інтерфейс Idisposable з єдиним методом Dispose, що звільняє зайняті ресурси:

    Public Interface Idisposable

    Sub Dispose()

    End Interface

    Отже, запам'ятаєте наступне правило:

    Якщо ваш клас використовує інший клас, реалізовуючий Idisposable, то в кінці роботи з ним необхідно викликати метод Dispose.

    Як буде показано в розділі 8, метод Dispose повинен викликатися в кожному графічному застосуванні, залежному від базового класу Component, оскільки це необхідно для звільнення графічних контекстів, використовуваних всіма компонентами.

    Список класів .NET Framework, що реалізовують інтерфейс Idisposabe (отже, що підтримують метод Dispose, який повинен викликатися в додатках), приведений в описі інтерфейсу Idisposable в електронній документації.

    Колекції

    Колекцією (collection) називається об'єкт, призначений для зберігання інших об'єктів. Колекція містить методи для включення і видалення внутрішніх об'єктів, а також звернення до них в різних варіантах — від простої індексації, як при роботі з масивами, до складної вибірки по ключу, як в класі Hashtable, представленому в попередньому розділі. .NET Framework містить немало корисних класів колекцій. Розширення цих класів за допомогою спадкоємства дозволяє будувати спеціалізовані колекції, безпечні по відношенню до типів. Та все ж при нетривіальному використанні вбудованих класів колекцій необхідно знати, які інтерфейси в них реалізовані. Декілька найближчих розділів присвячено стандартним інтерфейсам колекцій.

    For Each і інтерфейс lenumerable

    Підтримка For-each в класах Vb6 була недостатньо інтуїтивною, а її синтаксис сприймався як щось досконале чужорідне (ми згадували про це в розділі 1). У VB .NET існують два способи організації підтримки For-each в класах колекцій. Перший метод вже був продемонстрований вище: новий клас визначається похідним від класу з підтримкою For-each і автоматично успадковує його функціональність. Зокрема, цей спосіб застосовувався для класу Empl oyees, похідного від класу System. Collections. Collectionbase.

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

    Public Interface lenumerable

    Function Getenumerator() As Enumerator

    End Interface

    При реалізації lenumerable клас реалізує метод Getenumerator, який повертає об'єкт Ienumerator, що забезпечує можливість перебору в класі. Метод переходу до наступного елементу колекції визначається саме в інтерфейсі Ienumerator, який визначається таким чином:

    Public Interface lenumerator

    Readonly Property Current As Object

    Function Movenext() As Boolean

    Sub Reset ()

    End Interface

    У циклі For-each перебір ведеться тільки в одному напрямі, а елементи доступні тільки для читання. Цей принцип абстрагований в інтерфейсі lenumerator — в інтерфейсі присутній метод для переходу до наступного елементу, але немає методів для зміни даних. Крім того, в інтерфейс Ienumerator повинен входити обов'язковий метод для переходу в початок колекції. Зазвичай цей інтерфейс реалізується способом включення (containment): у колекцію упроваджується спеціальний клас, якому передоручається виконання трьох інтерфейсних методів (один з lenumerable і два з Ienumerator).

    Нижче приведений приклад колекції Employees, побудованої «на порожньому місці». Звичайно, клас виходить складнішим, ніж при простому спадкоємстві від System. Collections. Collectionbase, та зате він володіє набагато більшими можливостями. Наприклад, замість послідовного повернення об'єктів Employee можна використовувати сортування по довільному критерію:

    1 Public Class Employees

    2 Implements Ienumerable.IEnumerator

    3 Private m_employees() As Employee

    4 Private m_index As Integer = -1

    5 Private m_count As Integer = 0

    6 Public Function Getenumerator() As lenumerator _

    7 Implements lenumerable.GetEnumerator

    8 Return Me

    9 End Function

    10 Public Readonly Property Current() As Object _

    11 Implements Ienumerator.Current

    12 Get

    13 Return m_employees(m_index)

    14 End Get

    15 End Property

    16 Public Function Movenext() As Boolean _

    17 Implements lenumerator.MoveNext

    18 If m_index < m_count Then

    19 m_index += 1

    20 Return True

    21 Else

    22 Return False

    23 End If

    24 End Function

    25 Public Sub Reset() Implements Ienumerator.Reset

    26 m_index = 0

    27 End Sub

    28 Public Sub New(Byval theemployees() As Employee)

    29 If theemployees Is Nothing Then

    30 Msgbox("No items in the collection")

    31 ' Ініціювати виключення - див. розділ 7

    32 ' Throw New Applicationexception()

    33 Else

    34 m_count = theemployees.Length - 1

    35 m_employees = theemployees

    36 End If

    37 End Sub

    38 End Class

    Рядок 2 повідомляє про те, що клас реалізує два основні інтерфейси, використовуваних при роботі з колекціями. Для цього необхідно реалізувати функцію, яка повертає об'єкт lenumerator. Як видно з рядків 6-9, ми просто повертаємо поточний об'єкт Me. Втім, для цього клас повинен містити реалізації членів Ienumerable; вони визначаються в рядках 10-27.

    У приведеній вище програмі є одна тонкість, яка не має ніякого відношення до інтерфейсів, а швидше пов'язана із специфікою класу. У рядку 4 змінна mjndex ініціалізувалася значенням -1, що дає нам доступ до 0 елементу масиву, внаслідок чого перший виклик Movenext надає доступ до елементу масиву з індексом 0 (спробуйте ініціалізувати mjndex значенням 0, і ви переконаєтеся, що при цьому втрачається перший елемент масиву).

    Нижче приведена невелика тестова програма. Передбачається, що Publiс-класс Employee входить в рішення:

    Sub Main()

    Dim torn As New Emplpyee("Tom". 50000)

    Dim sally As New Employee("Sally". 60000)

    Dim joe As New Employee("Joe", 10000)

    Dim theemployees(l) As Employee

    theemployees(0) = torn

    theemployees(1) = sally

    Dim myemployees As New Employees(theemployees)

    Dim aemployee As Employee

    For Each aemployee In myemployees

    Console.WriteLine(aemployee.TheName)

    Next

    Console.ReadLine()

    End Sub




    :: Наша кнопка ::

    Отримати код:

    Підтримайте наш сайт і розмістіть нашу кнопку на своєму ресурсі.


    :: Реклама ::

    Скачати безкоштовно програму Microsoft Front Page 2003


    :: Посилання ::

    -


     

     

     


    Copyright ©