Целта на абстрактните членове е да
поддържат сигнатурата на членовете (atemplate) които могат да бъдат изпълнени от един
или повече произхождащи класа (derived classes), генерално по различни начини.
Да изясним това с пример. Обратно към дискусията за
наследяемост с класа CSlujasht , дефиниращ и изпълняващ метода IncZaplata , който увеличава {инкрементира} заплатата на служителя. Да си припомним, че
произхождащите класове CDirector и CSecretary използват - override изпълнението на метода IncZaplata в базовия клас CSlujasht. Допускаме,
че в комплексен модел за Служител, има произхождащи класове за всеки тип служител. Нещо повече, всеки от тези произхождащи класове предефинира (overrides) изпълнението на метода IncZaplata от базовия клас CSlujasht. В този случай, изпълнение на IncZaplata в базовия клас никога няма да бъде повиквано! Защо да има такъв член за
изпълнение и никога да не се използва в базовия клас?
Наместо това, можем просто да поддържаме празен метод IncZaplata, както е показано тук:
' Slujasht class
Public Class CSlujasht
. . .
Public Overridable Sub IncZaplata(ByVal
sngPercent As Single)
End Sub
End Class
Алтернативно ако бихме изискали (require) всички произхождащи класове да използват метод IncZaplata, можем да използваме ключова
дума MustOverride както е показано тук:
' Slujasht class
Public MustInherit Class CSlujasht
. . .
Public MustOverride Sub IncZaplata(ByVal
sngPercent As Single)
End Class
Както посочихме вече, когато използваме MustOverride, няма инструкция End
Sub асоциирана с
метода. Ако използвате ключова дума MustOverride, Microsoft изисква класа да бъде
деклариран с ключова дума MustInherit. Това спесифицира, че не можем
да създаваме обекти от тип CSlujasht. Във всеки от предишните случаи, членът IncZaplata от базовия клас CSlujasht е абстрактен член. Всеки клас, който съдържа поне
един абстрактен член се нарича абстрактен клас - abstract class. (Така клас CSlujasht е абстрактен клас.) Терминологията идва от това, че не е
възможно да се създаде обект от абстрактен клас, защото най-малко един от
обектните методи няма имплементация (изпълнение).
Може да съществува ситуация в която може да искаме да
дефинираме клас, в който всички членове са абстрактни. С други думи клас, който само дефинира (defines) интерфейс. Можем да се свързваме с такъв
клас като чисто абстрактен клас (pure abstract). Примерно
инструмента Shape клас именуван CShape който е проектиран за модел на генералните свойства и акции
на геометрични фигури (eлипси, правоъгълници, трапеци). Всички фигури се нуждаят от метод Draw, но изпълнението на метода варира в зависимост от типа фигура. Подобни са методи Rotate, Translate, и Reflect.
Да дефинираме класа CShape:
Public Class Class2
Public Overridable Sub
Draw( )
End Sub
Public Overridable Sub
Rotate(ByVal sngDiplomi As Single)
End Sub
Public Overridable Sub Translate(ByVal
x As Integer, _
ByVal y As Integer)
End Sub
Public Overridable Sub
Reflect(ByVal iSlope As Integer, _
ByVal iIntercept As
Integer)
End Sub
End Class
или:
Public MustInherit Class
CShape
Public MustOverride Sub
Draw( )
Public MustOverride Sub
Rotate(ByVal sngDiplomi As Single)
Public MustOverride Sub
Translate(ByVal x As Integer, _
ByVal y As Integer)
Public MustOverride Sub
Reflect(ByVal iSlope As Integer, _
ByVal iIntercept As
Integer)
End Class
Сега можем да дефинираме произхождащи класове CRectangle, CEllipse, CPolygon.
Всеки от тези произхождащи класове ще изпълнява (или трябва, във втория случай) членове на базовия клас CShape.
- Interfaces Revisited
Видяхме, че интерфейси могат да се дефинират в модули клас. VB .NET поддържа допълнителен метод за
дефиниране на интерфейс, използвайки Interface ключова дума. Следният пример дефинира интерфейс IShape:
Public Interface IShape
Sub Draw( )
Sub Rotate(ByVal sngDiplomi
As Single)
Sub Translate(ByVal x As
Integer, ByVal y As Integer)
Sub Reflect(ByVal iSlope As
Integer, ByVal iIntercept As Integer)
End Interface
Не можем да изпълним (implement) никой от членовете
на интерфейса, дефиниран с Interface , вътре от модула, където интерфейса е
дефиниран. Но можем да изпълним интерфейса използвайки ординарен клас модул.
Отбележете използването на инструкция Implements (достъпен и във VB 6):
Public Class CRectangle
' изпълнява -Implement интерфейса IShape
Implements IShape
Public Overridable Sub
Draw( ) Implements IShape.Draw
' код за начертаване (Draw) на правоъгълник
End Sub
Public Overridable Sub
Spin( ) Implements IShape.Rotate
' код за изпълнение на Rotate на правоъгълник
End Sub
End Class
Вижте как се използва ключова дума Implements
във всяка функция,
която изпълнява интерфейсен член. Тази ключова дума ни позволява да
дадем на изпълнителната функция някакво име--не е нужно да съвпада с
името на
метода (вижте метод Spin, който изпълнява IShape интерфейсния метод Rotate).
Може би е по-добра практика да се
използва същото име. Основното предимство при използването на ключова
дума Implements за дефиниране на интерфейс е, че отделен клас може да
изпълнява
много интерфейси, докато VB .NET не позволява на отделния клас да
наследява директно от много
базови класове. От друга страна основния недостатък , при използването
на ключова дума Implements e че не е възможно изпълнение, в
модула, където е дефиниран интерфейса.
Използването на
ключова дума Implements се е променило от версия 6.0 на Visual Basic. Инструкцията Implements ви позволява своеобразна форма на
наследяемост във Visual Basic .NET. Вие можете да изпълните (implement) клас или интерфейс във Visual Basic .NET с инструкция Implements.
Ето пример:
Public function TestFoo
(ByVal sWork as String) as Integer
Implements ImyInterface.Run
Интерфейсът включва методите и обектите, които класа
представя на консуматорите си. В програмирането на COM, фундаментално правило е,че след като се публикува интерфейса, не
може да се променя. Интерфейсите
се дефинират в клас с инструкция Interface; можете да дефинирате подпрограми (subs), функции (functions), събития (events), и свойства (properties) в
интерфейси:
Public Interface
MyInterface
Sub subOne()
Sub SubTwo()
End Interface
Интерфейсът може да бъде и функция:
Public Sub subOne(ByVal
sSoftDrink As String) as Integer
Този кодов фрагмент дефинира метод subOne , който има параметър sSoftdrink. Според
правилата в COM, ако променим интерфейса, той
създава нов обект. Класът може да наследява от друг клас интерфейс чрез инструкция Implements. Когато изпълнявате клас,
създавате всички методи и свойства съдържащи се в изпълнения клас или
интерфейс. Това ще предизвика грешка. Eдинственият код, който е нужен в
интерфейса е неговата дефиниция.