ПОНЯТНО О Visual Basic NET (том 3)

       

Конструкторы


Смысл конструктора. Вы знаете, что если у вас в окне кода формы присутствует процедура 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.Владелец обозначает глобальную переменную.

Аналогичные рассуждения можно провести и для других параметров.


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