Иллюстрированный самоучитель по VB.NET

       

Абстрактные базовые классы


Абстрактные базовые классы

На стадии проектирования наследственных связей в программе часто выясняется, что многие классы обладают целым рядом сходных черт. Например, внештатные сотрудники не относятся к постоянным работникам, но и те и другие обладают рядом общих атрибутов — именем, адресом, кодом налогоплательщика и т. д. Было бы логично выделить все общие атрибуты в базовый класс Payabl eEnt i ty. Этот прием, называемый факторингом, часто используется при проектировании классов и позволяет довести абстракцию до ее логического завершения.

В классах, полученных в результате факторинга, некоторые методы и свойства невозможно реализовать, поскольку они являются общими для всех классов в иерархии наследования. Например, класс Payabl eEnt i ty, от которого создаются производные классы штатных и внештатных работников, может содержать свойство с именем TaxID. Обычно в процедуре этого свойства следовало бы организовать проверку кода налогоплательщика, но для некоторых категорий внештатных работников эти коды имеют особый формат. Следовательно, проверка этого свойства должна быть реализована не в базовом классе Payabl eEntity, а в производных классах, поскольку лишь они знают, как должен выглядеть правильный код.

В таких ситуациях обычно определяется абстрактный базовый класс. Абстрактным называется класс, содержащий хотя бы одну функцию с ключевым словом MustOverride; при этом сам класс помечается ключевым словом Mustlnherit. Ниже показано, как может выглядеть абстрактный класс Payabl eEntity:

Public Mustlnherit Class PayableEntity

Private m_Name As String

Public Sub New(ByVal itsName As String)

m_Name = itsName

End Sub

Readonly Property TheName()As String

Get



Return m_Name

End Get

End Property

Public MustOverride Property TaxID()As String

End Class

Обратите внимание: свойство TaxID, помеченное ключевым словом MustOverride, только объявляется без фактической реализации. Члены классов, помеченные ключевым словом MustOverride, состоят из одних заголовков и не содержат команд End Property, End Sub и End Function.
Доступное только для чтения свойство TheName при этом реализовано; из этого следует, что абстрактные классы могут содержать как абстрактные, так и реализованные члены. Ниже приведен пример класса Егор! оуее, производного от абстрактного класса PayableEntity (ключевые строки выделены жирным шрифтом):

Public Class Employee

Inherits PayableEntity

Private m_Salary As Decimal

Private m_TaxID As String

Private Const LIMIT As Decimal = 0.1D

Public Sub NewCByVal theName As String, ByVal curSalary As Decimal.

ByVal TaxID As String) MyBase.New(theName)

m_Salary = curSalary

m_TaxID = TaxID End Sub

Public Overrides Property TaxID() As String Get

Return m_TaxID

End Get

Set(ByVal Value As String)

If Value.Length <> 11 then

' См. главу 7 Else

m_TaxID = Value

End If

End Set

End Property

Readonly Property Salary() As Decimal Get

Return MyClass.m_Salary

End Get

End Property

Public Overridable Overloads Sub RaiseSalary(ByVal Percent As Decimal)

If Percent > LIMIT Then

' Операция запрещена - необходим пароль

Console.WriteLineC'NEED PASSWORD TO RAISE SALARY MORE " & _

"THAN LIMIT!!!!") Else

m_Salary =(1D + Percent) * m_Salary

End If

End Sub

Public Overridable Overloads Sub RaiseSalary(ByVal Percent As

Decimal. ByVal Password As String) If Password ="special" Then

m_Salary MID + Percent) * m_Salary

End If

End Sub

End Class

Первая ключевая строка расположена внутри конструктора, который теперь должен вызывать конструктор абстрактного базового класса для того, чтобы правильно задать имя. Во втором выделенном фрагменте определяется элементарная реализация для свойства Taxld, объявленного с ключевым словом MustOverride (в приведенном примере новое значение свойства не проверяется, как следовало бы сделать в практическом примере).

Ниже приведена процедура Sub Mai n, предназначенная для тестирования этой программы:

Sub Main()

Dim tom As New Employee("Tom". 50000. "111-11-1234")



Dim sally As New Programmed "Sally", 150000. "111-11-2234".)

Console.Wri teLi ne(sa1ly.TheName)

Dim ourEmployees(l) As Employee

ourEmployees(0) = tom

ourEmployees(l) = sally

Dim anEmployee As Employee

For Each anEmployee In ourEmployees anEmployee.RaiseSalary(0.lD)

Console.WriteLine(anEmployee.TheName & "has tax id " & _

anEmployee.TaxID & ".salary now is " & anEmployee.Salary())

Next

Consol e.ReadLine() End Sub

В программе невозможно создать экземпляр класса, объявленного с ключевым словом Mustlnherit. Например, при попытке выполнения следующей команды:

Dim NoGood As New PayableEntity("can't do")

компилятор выводит сообщение об ошибке:

Class 'PayableEntity' is not creatable because it contains at least one member marked as 'MustOverride' that hasn't been overridden.

Тем не менее объект производного класса можно присвоить переменной или контейнеру абстрактного базового класса, что дает возможность использовать в программе полиморфные вызовы:

Dim torn As New Employee("Tom". 50000, "123-45-6789")

Dim whoToPay(13) As PayableEntity whoToPay(0) = tom

Теоретически класс Mustlnherit может не содержать ни одного члена с ключевым сло-вом MustOverride (хотя это будет выглядеть несколько странно).




Содержание раздела