Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСНОВЫ ОФИСНОГО ПРОГРАММИРОВАНИЯ И ЯЗЫК VBA - 1....doc
Скачиваний:
59
Добавлен:
17.12.2018
Размер:
1.88 Mб
Скачать

Семейство классов и процедуры - свойства

Когда создается семейство классов, без свойств - участников не обойтись. В классах семейства, основанных на механизме встраивания, обязательно есть свойства, представляющие собой объекты. Эти свойства, как и терминальные, обычно, закрываются и для работы с ними используются процедуры - свойства Property Set и Property Get. Иногда приходится передавать и дополнительные параметры при работе с ними. Рассмотрим типичный пример. Ранее мы построили класс "Личность", теперь построим класс "Группа", содержащий группу личностей. При построении этого класса ограничимся минимальными средствами, необходимыми для демонстрации работы со свойствами:

'Класс Группа Личностей

Const РазмерГруппы As Byte = 25

'Свойства

Private Group(1 To РазмерГруппы) As Личность

'Процедуры-свойства

Public Property Get ЧленГруппы(num As Byte) As Личность

'Если номер корректен

If (num >= 1) And (num <= РазмерГруппы) Then

'Если существует в группе личность с таким номером

If Not (Group(num) Is Nothing) Then

Set ЧленГруппы = Group(num)

Else: MsgBox ("В группе нет человека с номером " & num)

End If

Else: MsgBox ("Некорректно задан номер в группе - " & num)

End If

End Property

Public Property Set ЧленГруппы(num As Byte, NewValue As Личность)

'Если номер корректен

If (num >= 1) And (num <= РазмерГруппы) Then

'Если в группе нет личности с таким номером, то она создается

If Group(num) Is Nothing Then

Set Group(num) = NewValue

Else: MsgBox ("В группе уже есть человек с номером " & num)

End If

Else: MsgBox ("Некорректно задан номер в группе - " & num)

End If

End Property

Public Sub Сведения()

Dim i As Byte

For i = 1 To РазмерГруппы

If Not (Group(i) Is Nothing) Then

Group(i).PrintPerson

End If

Next i

End Sub

Пример 4.4. (html, txt)

Массив объектов класса "Личность" является закрытым свойством класса "Группа". Процедуры - свойства Property Get ЧленГруппы и Property Set ЧленГруппы обеспечивают доступ к элементам этого массива. Индекс элемента является дополнительным параметром. Заметьте, процедура Set имеет статус Write-once, - если элемент с заданным номером уже определен в группе, то он не переопределяется. При создании этих процедур, нам, конечно же, пришлось модифицировать стандартные заготовки Let и Get. Для полноты картины приведем процедуру, в которой показано, как работать с группой:

Public Sub WorkWithGroup()

Dim UserOne As New Личность

Dim UserTwo As New Личность

Dim UserThree As New Личность

Dim Знакомые As New Группа

Dim NewUser As New Личность

'Личности

UserOne.InitPerson FN:="Петр", LN:="Петров", DoB:=#1/23/1968#

UserTwo.InitPerson FN:="Анна", LN:="Козлова", DoB:=#7/21/1968#

UserThree.InitPerson FN:="Анна", LN:="Керн", DoB:=#5/17/1803#

'Группа

Set Знакомые.ЧленГруппы(1) = UserOne

Set Знакомые.ЧленГруппы(2) = UserTwo

Set Знакомые.ЧленГруппы(1) = UserThree

Set Знакомые.ЧленГруппы(3) = UserThree

Set NewUser = Знакомые.ЧленГруппы(7)

Set NewUser = Знакомые.ЧленГруппы(3)

Знакомые.Сведения

End Sub

Не останавливаясь на тех диалогах, которые будут появляться по ходу выполнения, приведем результаты печати сведений о наших старых знакомых:

Петр Петров родился 23.01.68

Анна Козлова родилась 21.07.68

Анна Петровна Керн родилась 17.05.1803

Мы уже говорили о том, что классы могут выступать в роли привлекательной упаковки при работе со служебными функциями. Такую же "упаковочную" роль они могут играть и при работе со встроенными объектами. Свойствами такого класса могут быть, например, элементы управления, - списки, кнопки. Класс - упаковка позволит обращаться к методам и свойствам объекта, может быть в более привлекательной для конечного пользователя форме. Кроме того, в классе могут быть определены и дополнительные свойства и методы, расширяющие стандартные возможности.

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

Методы

Не будем повторяться. О методах было сказано уже достаточно. Любая процедура (Sub) или функция (Function), описанная в разделе методов класса, является его методом. Напомним синтаксис методов класса:

[Private | Public | Friend] [Static] Sub name [(arglist)]

[statements]

[Exit Sub]

[statements]

End Sub

[Public | Private | Friend] [Static] Function name [(arglist)] [As type]

[statements]

[name = expression]

[Exit Function]

[statements]

[name = expression]

End Function

Роль всех ключевых слов в этих определениях уже пояснялась, чуть позже мы подробнее скажем о спецификаторе Friend, который могут иметь методы класса. Сейчас же отметим, что почти каждый класс, независимо от его специфики имеет некоторый "джентльменский" набор методов. В него входит:

  • Один или несколько конструкторов класса, в том числе конструктор по умолчанию, заданный обработчиком события Initialize.

  • Обычно, по паре процедур - свойств, определенных для каждого свойства класса.

  • Метод, задающий печать свойств класса.

  • Метод, позволяющий в диалоге с пользователем определять значения свойств класса, - своеобразный конструктор.

  • Остальные методы, определяющие специфику класса.

Вернемся к проектированию класса Rational. Большую часть джентльменского его набора мы уже определили. Специфика этого класса определяется операциями над рациональными числами. Ограничимся четырьмя основными операциями - сложением, вычитанием, умножением и делением. Добавим к ним еще и метод печати дробей. Вот тексты этих методов, заканчивающих определение нашего класса:

Public Function Plus(a As Rational) As Rational

Dim d As Integer, u As Integer, v As Integer

Dim R As New Rational

u = m * a.Знаменатель + n * a.Числитель

v = n * a.Знаменатель

d = nod(u, v)

R.Числитель = u \ d

R.Знаменатель = v \ d

Set Plus = R

End Function

Public Function Minus(a As Rational) As Rational

Dim d As Integer, u As Integer, v As Integer

Dim R As New Rational

u = m * a.Знаменатель - n * a.Числитель

v = n * a.Знаменатель

d = nod(u, v)

R.Числитель = u \ d

R.Знаменатель = v \ d

Set Minus = R

End Function

Public Function Mult(a As Rational) As Rational

Dim d As Integer, u As Integer, v As Integer

Dim R As New Rational

u = m * a.Числитель

v = n * a.Знаменатель

d = nod(u, v)

R.Числитель = u \ d

R.Знаменатель = v \ d

Set Mult = R

End Function

Public Function Divide(a As Rational) As Rational

Dim d As Integer, u As Integer, v As Integer

Dim R As New Rational

u = m * a.Знаменатель

v = n * a.Числитель

If v = 0 Then

MsgBox ("деление на нуль невозможно")

Else

d = nod(u, v)

R.Числитель = u \ d

R.Знаменатель = v \ d

Set Divide = R

End If

End Function

Public Sub PrintRational()

Debug.Print (m & "/" & n)

End Sub

Пример 4.5. (html, txt)

Замечание:

Внутри класса при реализации операций над рациональными числами доступ к закрытым свойствам объекта, естественно, разрешен, и можно обращаться непосредственно к переменным m и n. Однако нельзя обратиться к закрытым свойствам параметров класса Rational, передаваемых методам Plus, Minus, Mult, Divide. Точно также, нельзя обратиться к свойствам локальных объектов (объекту R), объявленных внутри методов. Единственный выход состоит в том, чтобы использовать для них Public Property Let и Public Property Get. Но тогда и вне класса можно использовать эти процедуры - свойства, изменяя, например, значение знаменателя дроби. Разрешать этого не хотелось бы.

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

Приведем процедуру, которая работает с рациональными числами:

Public Sub WorkWithRational()

Dim a As New Rational, b As New Rational, c As New Rational

a.CreateRational 5, 7

b.CreateRational -12, -18

Set c = a.Plus(b)

c.PrintRational

Set a = c.Minus(b)

a.PrintRational

Set c = a.Mult(b)

c.PrintRational

Set b = c.Divide(a)

b.PrintRational

End Sub

При ее запуске получены следующие результаты:

29/21

5/7

10/21

2/3