Абстрактные классы
Владельцы участков в нашем товариществе стали огораживать их всяк на свой манер: у одних участки прямоугольные, у других треугольные, у третьих круглые. Для нашего проекта это значит, что периметры теперь нужно считать по разным формулам. Соответственно создаем три класса: Участок_прямоугольный, Участок_треугольный и Участок_круглый. Их коды во многом одинаковы и различаются только исходными данными и функцией Периметр. Следовательно, целесообразно организовать наследование. Но кто кого будет наследовать? Вроде, все три класса равноправны. Из соображений стройности и логичности системы классов нам не хочется один из них делать родителем. Что же делать? Поступают так. Создают один класс, родительский для всех трех, и включают в него код, общий для всех трех классов. Поскольку функция Периметр разная для всех классов, то в этот класс включают только ее заголовок, без тела. Ясно, что от такого бестелесного класса нельзя создавать объекты, поэтому его называют абстрактным классом и помечают словом MustInherit. Вот этот класс:
Public MustInherit Class Участок_абстрактный
Public Владелец As String
Public Высота_забора As Integer
Public Shared Расход_краски_на_кв_м As Integer
Public MustOverride
Function Периметр() As Integer
Public Overridable Function Площадь_забора() As Integer
Return Периметр() * Высота_забора
End Function
Public Function Расход_краски_на_забор() As Integer
Return Расход_краски_на_кв_м * Площадь_забора()
End Function
End Class
Вы видите, что функция в этом классе помечена словом MustOverride, что означает «Необходимо пересилить, переопределить». От функции присутствует только заголовок. Ситуация того же смысла, что и со словом Overridable, только более строгая. Это значит, что обращаться к функции в этом классе бесполезно, все равно у нее нет тела, а вот в коде наследников эту функцию написать можно и нужно, причем тело функции у каждого наследника может быть своим. К этим функциям и будем обращаться. Вот три наших класса:
Public Class Участок_прямоугольный
Inherits Участок_абстрактный
Public Длина, Ширина As Integer
Public Overrides
Function Периметр() As Integer
Return 2 * (Длина + Ширина)
End Function
End Class
Public Class Участок_треугольный
Inherits Участок_абстрактный
Public Сторона1, Сторона2, Сторона3
As Integer
Public Overrides
Function Периметр() As Integer
Return Сторона1 + Сторона2 + Сторона3
End Function
End Class
Public Class Участок_круглый
Inherits Участок_абстрактный
Public Радиус As Integer
Public Overrides
Function Периметр() As Integer
Return 2 * Math.PI * Радиус
End Function
End Class
Вы видите, что абстрактные классы помогают поддерживать в проекте стройную иерархию классов.
В нашу систему классов я могу включить и класс Участок_штакетник. Я сделаю его сыном прямоугольного участка и, значит, внуком абстрактного:
Public Class Участок_штакетник
Inherits Участок_прямоугольный
Public Overrides Function Площадь_забора() As Integer
Return 0.5 * MyBase.Площадь_забора
End Function
End Class
Вы видите, что он может посчитать площадь штакетника только вокруг прямоугольного участка. Вопрос о штакетнике вокруг треугольного и круглого участков оставляю открытым для вашего размышления.