
- •Тема 5.4. Иерархий классов, интерфейсы и исключения
- •5.4.1. Общие сведения о интерфейсах
- •5.4.2. Организация взаимодействия объектов
- •5.4.4. Обработка исключений в среде .Net Framework
- •5.4.5. Задачи для самостоятельного решения по теме «Иерархий классов, интерфейсы и исключения»
- •5.4.6. Тестовые задания по теме «Иерархий классов, интерфейсы и исключения»
Тема 5.4. Иерархий классов, интерфейсы и исключения
5.4.1. Общие сведения о и интерфейсах
5.4.2. Создание иерархий классов
5.4.3. Организация взаимодействия объектов
5.4.4. Обработка исключений в среде .NET Framework
5.4.5. Задачи для самостоятельного решения по теме «Иерархий классов, интерфейсы и
исключения»
5.4.6. Тестовые задания по теме «Иерархий классов, интерфейсы и исключения»
5.4.1. Общие сведения о интерфейсах
Интерфейсы, как и классы, определяют набор свойств, методов и событий. Но, в отличие от классов, интерфейсы не предоставляют реализацию. Они реализуются классами, но определяются как отдельные от классов сущности.
Интерфейс представляет собой контракт, в котором класс, реализующий интерфейс, должен реализовывать каждый аспект этого интерфейса в точном соответствии с его определением.
С помощью интерфейса свойства определяются в виде небольших групп тесно связанных членов. Расширенные реализации для интерфейсов разрабатываются без риска для существующего кода, поэтому проблемы совместимости минимизируются. Новые свойства также добавляются в любой момент времени с помощью разработки дополнительных интерфейсов и реализаций.
Несмотря на то, что реализации интерфейсов можно развивать, сами интерфейсы нельзя изменить после публикации. Изменение опубликованного интерфейса способно нарушить работу существующего кода. Если интерфейс рассматривается как контракт, ясно, что важными являются обе стороны контракта. Издатель интерфейса соглашается никогда не изменять интерфейс, а реализатор соглашается реализовывать интерфейс строго в соответствии с его конструкцией.
В предыдущих версиях Visual Basic можно было использовать интерфейсы, не создавая их непосредственно. Теперь полноценные интерфейсы можно определить с помощью оператора Interface и реализовать интерфейсы с улучшенной версией ключевого слова Implements.
,
Интерфейсы (Visual Basic)
Интерфейсы определяют свойства, методы и события, которые классы могут реализовывать. Интерфейсы позволяют определить внешние представления в виде небольших групп тесно связанных свойств, методов и событий; при этом уменьшается количество проблем совместимости, поскольку. можно создавать усовершенствованные реализации интерфейсов без вмешательства в существующий код. Новые внешние представления добавляются в любой момент времени с помощью разработки дополнительных интерфейсов и реализаций.
Определения интерфейсов находятся между операторами Interface и End Interface.После оператора Interface можно добавить необязательный оператор Inherits, в котором представлен один или несколько наследуемых интерфейсов. Оператор Inherits предшествуют всем другим операторам в объявлении за исключением комментариев. Остальные операторы в определении интерфейса должны быть следующими: Event, Sub, Function, Property, Interface, Class, Structure и Enum. В интерфейсах не содержатся коды реализаций или операторы, связанные с кодом реализации, такие как End Sub или End Property.
В пространстве имен операторы интерфейса по умолчанию Friend, но также их можно явно объявить как Public или Friend. Интерфейсы, определенные в классах, модули, интерфейсы и структуры являются Public по умолчанию, но также их можно объявить явно как Public, Friend Protected или Private.
Ключевое слово Shadows может быть применено для всех членов интерфейса. Ключевое слово Overloads может быть применено к операторам Sub, Function и Property, объявленным в определении интерфейса. Кроме того, для операторов Property можно использовать модификаторы Default, ReadOnly или WriteOnly. Ни один из других модификаторов – Public, Private Friend, Protected, Shared, Overrides, MustOverride или Overridable не разрешен.
Например, следующий код определяет интерфейс с одной функцией, одним свойством и одним событием.
-
Interface IAsset
Event ComittedChange(ByVal Success As Boolean)
Property Division( ) As String
Function GetID( ) As Integer
End Interface
Зарезервированное слово Visual Basic Implements используется двумя способами. Инструкция Implements означает, что класс или структура реализуют интерфейс. Ключевое слово Implements обозначает, что элемент класса или структуры реализует элемент интерфейса.
Оператор Implements
Если класс или структура реализуют один или несколько интерфейсов, он должно включать инструкцию Implements сразу после инструкции Class или Structure. Инструкция Implements требует разделенный запятыми список интерфейсов, внедряемый с помощью класса. Класс или структура должны реализовать все элементы интерфейса с помощью ключевого слова Implements.
Ключевое слово Implements
Ключевое слово Implements требует разделенный запятыми список элементов интерфейса для внедрения. Как правило, указывается только один элемент интерфейса, но можно указать и несколько элементов. Спецификация элемента интерфейса обязательно состоит из имени интерфейса, которое должно быть указано в операторе Implements внутри класса, точки и имени реализуемой функции, свойства или события элемента. Для имени элемента класса, который реализует элемент интерфейса, можно использовать любой допустимый идентификатор.
Например
следующий код показывает способ
объявления подпрограммы с именем Sub1
,
которая реализует метод интерфейса:
-
Class Class1
Implements interfaceclass.interface2
Sub Sub1(ByVal i As Integer) Implements interfaceclass.interface2.Sub1
End Sub
End Class
Необходимо, чтобы типы параметров и возвращаемые типы элемента реализации соответствовали свойствам интерфейса или объявлению элементов в интерфейсе. Обычным способом реализации элемента интерфейса является способ с использованием элемента, имя которого совпадает с именем интерфейса (см. предыдущий пример).
Для объявления реализации метода интерфейса можно использовать любые допустимые атрибуты в объявлении метода экземпляра, включая Overloads, Overrides, Overridable, Public, Private, Protected, Friend, Protected Friend, MustOverride, Default и Static. Атрибут Shared не является допустимым, поскольку он определяет класс, а не метод экземпляра.
С помощью Implements можно также задать единственный метод, который реализует несколько методов, определенных в интерфейсе, как в следующем примере:
-
Class Class2
Implements I1, I2
Protected Sub M1() Implements I1.M1, I1.M2, I2.M3, I2.M4
End Sub
End Class
Можно использовать закрытый элемент для реализации элемента интерфейса. Если закрытый элемент реализует элемент интерфейса, он становится доступен через интерфейс, даже если он не доступен непосредственно через переменные класса.
Примеры реализации интерфейса
Необходимо, чтобы классы, реализующие интерфейс, реализовывали и все его свойства, методы и события.
В
следующем примере определяются два
интерфейса. Второй интерфейс, Interface2
,
наследует Interface1
и определяет дополнительное свойство
и метод.
-
Interface Interface1
Sub sub1(ByVal i As Integer)
End Interface
' Demonstrates interface inheritance.
Interface Interface2 Inherits Interface1
Sub M1(ByVal y As Integer)
ReadOnly Property Num() As Integer
End Interface
В
следующем примере реализуется интерфейс
Interface1
,
определенный в предыдущем примере:
-
Public Class ImplementationClass1 Implements Interface1
Sub Sub1(ByVal i As Integer) Implements Interface1.sub1
' Insert code here to implement this method.
End Sub
End Class
В
последнем примере реализуется Interface2
,
включающий метод, унаследованный от
Interface1
:
-
Public Class Implementation Class2 Implements Interface2
Dim INum As Integer = 0
Sub sub1(ByVal i As Integer) Implements Interface2.sub1
' Insert code here that implements this method.
End Sub
Sub M1(ByVal x As Integer) Implements Interface2.M1
' Insert code here to implement this method.
End Sub
ReadOnly Property Num() As Integer Implements Interface2.Num
Get
Num = INum
End Get
End Property
End Class
Определение интерфейса Visual Studio ,
Определения интерфейсов находятся между операторами Interface и End Interface. После оператора Interface можно добавить необязательный оператор Inherits, в котором представлен один или несколько наследуемых интерфейсов. Оператор Inherits предшествуют всем другим операторам в объявлении за исключением комментариев. Остальные операторы в определении интерфейса должны быть следующими: Event, Sub, Function, Property, Interface, Class, Structure и Enum. В интерфейсах не содержатся коды реализаций или операторы, связанные с кодом реализации, такие как End Sub или End Property.
В пространстве имен операторы интерфейса по умолчанию Friend, но также их можно явно объявить как Public или Friend. Интерфейсы, определенные в классах, модули, интерфейсы и структуры являются Public по умолчанию, но также их можно объявить явно как Public, Friend Protected или Private.
Ключевое слово Shadows может быть применено для всех членов интерфейса. Ключевое слово Overloads может быть применено к операторам Sub, Function и Property, объявленным в определении интерфейса. Кроме того, для операторов Property можно использовать модификаторы Default, ReadOnly или WriteOnly. Ни один из других модификаторов — Public, PrivateFriend, Protected, Shared, Overrides, MustOverride или Overridable не разрешен.
Разработка интерфейсов
Класс, в котором отсутствует код реализации методов, а определены только имена и типы возвращаемых значений и список параметров, называется абстрактным, и методы также называются абстрактными. При объявлении абстрактных методов наследующий класс должен поддерживать собственную реализацию каждого абстрактного метода, то есть каждый абстрактный метод определяет способ вызова метода, но не его реализацию. Исходя из важности абстрактных классов и методов, расширим рассматриваемую концепцию, введя понятие интерфейса.
Интерфейс определяет методы, которые могут быть реализованы с помощью класса. В дополнение к объявлению сигнатур методов интерфейс может определять сигнатуры свойств. Он является чисто логической структурой, описывающей поддерживаемые классом методы и не указывающей при этом, что именно следует делать. Класс должен иметь код методов, поддерживаемых данным интерфейсом При этом каждый класс может свободно определять особенности реализации собственных методов.
Объявление интерфейса выполняется с помощью ключевого слова Interface.
Объявление и реализация интерфейса
Public Interface Iaccount
Function GetAccountInfo() As String
End Interface
Сразу после определения интерфейса он должен быть реализован одним или несколькими классами. Для этого необходимо после объявления класса указать название интерфейса вместе с ключевым словом Implements. Если класс реализует интерфейс, все методы этого интерфейса должны быть общедоступными. Ниже приведен код, демонстрирующий, как интерфейс IAccount реализован внутри класса CheckingAccount и SavingsAccount. Класс, реализующий интерфейс, указывается посредством ключевого слова Implements. Кроме того, данное слово используется для обозначения места вызова метода, реализующего интерфейс. Таким образом указывается, какой метод, объявленный в интерфейсе реализуется.
-
Public Class CheckingAccount Implements Iaccount Public Function GetAccountInfo() As String _
Implements IAccount.GetAccountInfo
Return "Printing Checking Account Info" End Function
End Class
Public Class SavingsAccount Implements IAccount
Public Function GetAccountInfo() As String _ Implements Iaccount.GetAccountInfo Return "Printing Savings Account Info" End Function
End Class
Поскольку концепция наследования абстрактного базового класса и концепция интерфейса имеют много общего, может возникнуть вопрос о целесообразности применения последнего. Аргументом в его пользу является то, что программисту предоставляется возможность создавать несколько интерфейсов для одного класса. Кроме того, в коде можно создавать ссылки на любой объект, который поддерживает его интерфейс. В результате удается полностью реализовать концепцию полиморфизма, называемую «один интерфейс, несколько методов».
Еще одна важная особенность объектно-ориентированного программирования связанная с иерархией классов, состоит в возможности послать одинаковые сообщения сразу нескольким объектам различных классов. Объектам предоставляется право выбрать, кто из них будет это сообщение обрабатывать. Другими словами, полиморфизм – это способность объектов, принадлежащих разным классам реагировать на один и тот же вызов метода с помощью собственной реализации метода, что значительно упрощает создание приложений, при их разработке не нужно беспокоиться о том, к объектам какого класса должен обращаться код поскольку данные классы поддерживают одинаковые интерфейсы. Допустим, требуется, чтобы все выполняющие обработку банковских счетов классы содержали метод GetAccountInfo, реализация которого в каждом классе зависит от типа счета, а интерфейс используемых классов одинаков. В коде приложения можно организовать цикл обработки счетов, а в процессе выполнения кода компилятор сам будет определять, метод какого класса должен быть реализован. Если в дальнейшем добавить еще один тип счета, который должен обрабатывать метод GetAccountInfo, то не придется вносить изменения в код приложения. Таким образом, реализовать концепцию полиморфизма в VB. NET можно, либо используя механизм наследования либо реализуя интерфейсы.
Приведенный ниже пример демонстрирует использование наследования. Сначала в программе создается базовый класс Account и производные классы SavingsAccount и CheckingAccount.
-
Реализация полиморфизма с использованием наследования
Public MustInherit Class Account
Public MustOverride Function GetAccountInfo() As String
End Class
Public Class CheckingAccount
Inherits Account
Public Overrides Function GetAccountInfo() As String
Return "Printing Checking Account Info"
End Function
End Class
Public Class SavingsAccount
Inherits Account
Public Overrides Function GetAccountInfo() As String Return "Printing Savings Account Info"
End Function End Class
Затем создается класс коллекции, которая будет содержать классы типа Account.
Imports System Collections CollectionBase Public Class AccountCollection
Inherits CollectionBase
Public Sub Add(ByVal value As Object) list.Add(value)
End Sub
Public Sub Remove(ByVal value As Object) list.Remove(value)
End Sub End Class
Потом организуется цикл по элементам созданного класса коллекции и вызывается метод GetAccountInfo каждого из них.
Dim oAccountCollection As AccountCollection = New AccountCollection()
Dim oCheckAccount As Account = New CheckingAccount()
Dim oSavingsAccount As Account = New SavmgsAccount()
oAccountCollection.add(oCheckAccount) oAccountedlection.add(oSavingsAccount)
Dim oItem as Account
For Each oItem In oAccountCollection
MsgBox(oItem.GetAccountlnfo)
Next
Того же результата можно добиться, используя интерфейсы. В этом случае вместо наследования базового класса Account следует определить и реализовать интерфейс Iaccount (
Реализация полиморфизма с использованием интерфейсов
-
Public Interface IAccount
Function GetAccountlnfo() As String End Interface
Public Class CheckingAccount Implements IAccount
Public Function GetAccountlnfo() As String _ Implements IAccount.GetAccountlnfo Return "Printing Checking Account Info" End Function
End Class
Public Class SavingAccount Implements IAccount
Public Function GetAccountInfo() As String _ Implements Iaccount.GetAccountInfo Return "Printing Savings Account Info"
End Function
End Class
Затем применяется класс коллекции для хранения интерфейсов типа IAccount
-
Dim oAccountCollection As AccountCollection = New AccountCollection() Dim oCheckAccount As IAccount = New CheckingAccount() Dim oSavmgsAccount As IAccount = New SavingsAccount() oAccountCol1ection.add(oCheckAccount) oAccountCol1ection.add(oSavingsAccount)
Далее в цикле вызывается метод GetAccountInfo объекта класса коллекции и выводится на экран окно с соответствующим сообщением:
-
Dim оItem As IAccount
For Each оItem In oAccountCol1ection
MsgBox(oItem GetAccountlnfo)
Next