Создаем и используем два объекта одного класса
В механике работы реальных объектов, создаваемых вами на компьютере, лучше всего разбираться на примере решения реальной задачи. Задачу возьмем максимально простую. Но перед тем, как ее решать, уточним терминологию.
Поля. С точки зрения грамматики языка VB данные, видимые снаружи, делятся на свойства и на поля. Будем называть полем (field) класса переменную, объявленную в этом классе при помощи слов Public или Friend:
Public C As Integer = 10
Свойства (Properties) определяются при помощи слова Property и мы разберем их чуть позже, в 22.5. Пока же будем иметь дело только с полями.
Снаружи класса поля и свойства неотличимы, обращение к ним одинаково. Это позволило мне в предыдущем разделе неформально называть и то и другое свойствами.
Внимательно разберитесь в нижеследующей задаче, так как она пройдет через добрую треть этой главы. С усложнением задачи будут усложняться и проекты для ее решения. Не забывайте копировать папки проектов.
Задача. Пусть вы – директор только что родившегося садово-дачного товарищества. В нем всего два участка (в следующем подразделе будет больше). Однако вы уже решили использовать компьютер для решения повседневных задач.
Как программист, вы решили создать класс Участок, в котором собрать все данные, характеризующие участок (например, размеры), и действия для вычисления нужных величин, касающихся участка (например, его площади).
Создайте проект из формы и класса Участок. Поместите на форму 5 текстовых полей и 3 кнопки. Проект должен действовать так:
Пользователь вводит в 5 текстовых полей следующую информацию, касающуюся первого участка:
- TextBox1 Владелец участка
- TextBox2 Длина участка
- TextBox3 Ширина участка
- TextBox4 Высота забора на участке
- TextBox5 Расход краски на 1 квадратный метр забора
После этого пользователь нажатием на кнопку 1 создает из класса Участок объект Участок1, который принимает в себя все данные из текстовых полей в качестве своих полей (не путайте поля объекта с текстовыми полями).
Private Sub Вычисляем_периметр()
Периметр = 2 * (Длина + Ширина)
End Sub
Private Function Площадь_забора() As Integer
Вычисляем_периметр()
Return Периметр * Высота_забора
End Function
Public Function Расход_краски_на_забор() As Integer
Return Расход_краски_на_кв_м * Площадь_забора()
End Function
End Class
Пояснения: Объекты совсем не обязательно объявлять и создавать в стандартном модуле, как мы это делали раньше. Сейчас, например, мы сделали это в модуле формы. Также совсем не обязательно объявлять и создавать их одним оператором, как мы делали раньше:
Dim Участок1 As New Участок
Можно сначала объявить (как мы сейчас и сделали):
Dim Участок1, Участок2 As Участок
а потом в удобный момент создать:
Участок1 = New Участок 'Из класса рождается объект
Заглянем в код класса. Мы видим там 5 переменных, объявленных словом Public. Следовательно, они видны снаружи объекта. Значит, это поля объекта. К тому же слово Public без употребления других запретительных слов (о них позже) допускает свободное изменение значений поля снаружи объекта. Следовательно, это поля для чтения-записи. Плачет наш принцип инкапсуляции! Зачем мы в нашей конкретной задаче сделали их таковыми? Затем, чтобы пользователь мог свободно задавать их значения из текстовых полей. Ничего не попишешь – таково требование задачи.
Внутренняя механика объекта определяется его процедурами и функциями. Единственной скромной задачей, которую мы поставили перед объектом, является подсчет расхода краски на забор вокруг участка. Для этого нам вполне хватило бы одной функции, но мы глядим вперед и вместо одной функции написали две функции и одну процедуру. Пояснения начинаю с геометрии.
Участки прямоугольные и не соприкасаются, значит длина забора вокруг участка равна периметру участка, а это две ширины плюс две длины. Площадь забора равна периметру, умноженному на высоту забора. Расход краски на весь забор равен ее расходу на 1 квадратный метр, умноженному на площадь забора.
Процедура Вычисляем_периметр вычисляет периметр. Мы сделали ее Private, так как пока никому снаружи она не нужна, всех интересует только расход краски. Если в будущем кому-то захочется вычислять периметр участка, поменяем Private на Public. По той же причине объявлена Private и переменная Периметр, которая ввиду этого полем не является и снаружи не видна. Класс Участок использует ее только как промежуточный результат вычислений.
Функция Площадь_забора возвращает площадь забора. Мы сделали ее Private из аналогичных соображений.
Функция Расход_краски_на_забор возвращает результат, который нужен снаружи (в нашем конкретном случае – процедуре Button3_Click, принадлежащей форме), поэтому мы сделали ее Public. Следовательно, эта функция является методом.
Зачем вместо одной функции мы написали две функции и одну процедуру? Потому что надеемся, что с развитием проекта нам может понадобиться вычислять, например, длину канавы вокруг участка, которая, очевидно, зависит от периметра, а значит готовенькая процедура, вычисляющая периметр, сократит наши усилия. Аналогично функция, возвращающая площадь забора, может понадобиться в будущем для вычисления количества досок для его замены.
Периметр тоже надо было вычислять функцией. Но я выбрал более корявый способ, чтобы показать, что в классе могут присутствовать не только функции, но и процедуры, и переменные, невидимые снаружи.
Итак, мы создали класс с пятью полями и одним методом. Кроме этого в нем есть переменная, процедура и функция, невидимые снаружи. Когда вы будете писать программный текст в окнах кода, вам удобнее будет сначала написать код класса, а уж потом код формы, потому что в этом случае при написании кода формы вы обнаружите, что после точки, поставленной за именем объекта, разворачивается удобный список его полей и методов.