Конструкторы
Смысл конструктора. Вы знаете, что если у вас в окне кода формы присутствует процедура Form1_Load, то она выполняется автоматически при загрузке формы. Аналогичная процедура может присутствовать и в коде класса. Ее имя New – и называется она конструктором. Она выполняется автоматически при создании объекта.
О конструкторах мы с вами говорили в 6.1.2 и 12.2.1, когда при помощи слова New создавали объекты из готовых классов, предоставленных нам библиотекой классов .NET Framework. Нынче мы создаем при помощи слова New объекты уже из собственных классов. Обратите внимание, что до сих пор нигде в коде классов мы не писали процедуры New, тем не менее объекты прекрасно создавались. Для чего же тогда нужен конструктор New? Для того же, для чего и процедура Form1_Load (ведь форма загружалась и при отсутствии этой процедуры) – а именно, чтобы произвести некоторые действия, которые программист считает нужным произвести в момент создания объекта из класса. Обычно это присвоение начальных значений переменным, открытие нужных файлов и т.п.
Пример конструктора. Давайте используем конструктор для присвоения в каждом объекте нужного значения полю Номер_участка. Сейчас оно у нас присваивается в модуле формы, что противоречит принципу инкапсуляции.
Уберем из кода формы строку
Участки(k).Номер_участка = k
Вместо этого вот как дополним наш класс:
Public Номер_участка As Integer
Private Shared
Число_созданных_объектов As Integer = 0
Public Sub New()
Число_созданных_объектов = Число_созданных_объектов + 1
Номер_участка = Число_созданных_объектов
End Sub
Здесь при создании очередного участка мы увеличиваем на 1 статическую переменную класса Число_созданных_объектов. Поэтому к моменту создания очередного участка эта переменная автоматически приобретает нужное значение, которое оператором
Номер_участка = Число_созданных_объектов
передается полю Номер_участка .
Конструктор с параметрами. Конструктор, как и всякая процедура, может иметь параметры. Обычно параметры используются для задания начальных значений переменным, полям и свойствам класса. Давайте зададим через параметры имя владельца, длину, ширину участка и высоту забора. Придумаем параметрам такие имена: Влад, Дл, Шир и Выс.
В учебных целях чуть изменим код класса – сделаем ширину модульной переменной. Вот получившийся код класса:
Public Class Участок
Public Владелец As String
Private Длина As Integer
Public Property Длина_участка() As Integer
Get
Return Длина
End Get
Set(ByVal Value As Integer)
If Value < 500 Then
Длина = Value
Else
MsgBox("Слишком длинный участок")
Длина = 0
End If
End Set
End Property
Private Ширина As Integer
Public Высота_забора As Integer
Public Shared Расход_краски_на_кв_м As Integer
Private Периметр As Integer
Public Номер_участка As Integer
Private Shared Число_созданных_объектов As Integer = 0
Public Sub New (ByVal Влад As String, ByVal Дл As Integer, ByVal Шир As Integer, ByVal Выс As Integer)
Владелец = Влад
Длина_участка = Дл
Ширина = Шир
Высота_забора = Выс
Число_созданных_объектов = Число_созданных_объектов + 1
Номер_участка = Число_созданных_объектов
End Sub
Private Sub Вычисляем_периметр()
Периметр = 2 * (Длина + Ширина)
End Sub
Private Function Площадь_забора() As Integer
Вычисляем_периметр()
Return Периметр * Высота_забора
End Function
Public Function Расход_краски() As Integer
Return Расход_краски_на_кв_м * Площадь_забора()
End Function
End Class
Для проверки работы конструктора нажмем на кнопку:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Участок.Расход_краски_на_кв_м = 3
Участки(1) = New Участок("Лиходеев", 5, 4, 2)
Debug.WriteLine(Участки(1).Расход_краски)
Участки(2) = New Участок("Берлага", 800, 5, 3)
Debug.WriteLine(Участки(2).Расход_краски)
End Sub
Для краткости я здесь отказался от текстовых полей.
Как видите, при помощи параметров конструктора мы можем задать значения полям Владелец и Высота_забора, свойству Длина_участка, а также добраться извне до модульной переменной Ширина, невидимой снаружи.
Обратите внимание, что при создании участка Берлаги свойство Длина_участка выдало сообщение, что участок слишком длинный. То есть свойство работает.
Проблема с именами. Мы придумали параметрам не очень-то хорошие имена. А зачем было вообще придумывать? Нельзя ли было обойтись старыми и написать так? –
Public Sub New(ByVal Владелец As String, ByVal Длина_участка As ……………………
Владелец = Владелец
Длина_участка = Длина_участка
………………………
Нельзя, потому что непонятно, чем отличается левая часть оператора присваивания от правой. А вот так писать можно:
Public Sub New(ByVal Владелец As String, ByVal Длина_участка
As Integer, _
ByVal Ширина
As Integer, ByVal Высота_забора As Integer)
Me.Владелец = Владелец
Me.Длина_участка = Длина_участка
Me.Ширина = Ширина
Me.Высота_забора = Высота_забора
Число_созданных_объектов = Число_созданных_объектов + 1
Номер_участка = Число_созданных_объектов
End Sub
Пояснения: Возьмем владельца. В теле процедуры встречаются две переменные с одинаковым именем Владелец. Одна из них объявлена в списке параметров процедуры и поэтому является в теле процедуры локальной. Другая объявлена в классе и является глобальной. Ясно, что локальная ее затеняет. Поэтому, когда мы пишем просто имя переменной Владелец, как написано в правой части оператора
Me.Владелец = Владелец
то компьютер понимает, что это параметр. Когда же мы в левой части упомянутого оператора написали Me с точкой, VB развернул перед нами список полей и свойств класса, откуда мы выбрали поле Владелец. Мы видим, что выражение Me.Владелец обозначает глобальную переменную.
Аналогичные рассуждения можно провести и для других параметров.