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

На рисунке 5.4 отражен один из моментов проектирования класса. Можно видеть, что в окне кода список объектов содержит объекты Class, Личность и Машина. При выборе объекта Class правый раскрывающийся список покажет список стандартных событий класса, а при выборе объектов Личность и Машина будет раскрываться список наследуемых методов.

увеличить изображение Рис. 5.4.  Проектирование класса ВладелецМашины

Определение семейства классов дано и нам осталось продемонстрировать работу с различными объектами этих классов. Главное, что хотелось показать, это совместную работу с объектами разных классов. Начнем с программного текста:

Option Explicit

'Модуль Примеры

Public FriendOne As New Личность

Public FriendTwo As New Личность

Public FriendThree As New Личность

Public carOne As New Машина

Public carTwo As New Машина

Public carThree As New Машина

Public OwnerOne As New ВладелецМашины

Public OwnerTwo As New ВладелецМашины

Public OwnerThree As New ВладелецМашины

Public FOne As New Личности

Public Sub Люди()

'Вызывается конструктор с параметрами

'и происходит знакомство с объектами

FriendOne.InitPerson FN:="Станислав", LN:="Федотов", _

DoB:="21.05.39"

FriendTwo.InitPerson FN:="Катя", LN:="Павлова", _

DoB:="22.03.79"

FriendThree.InitPerson FN:="Остап", LN:="Бендер", DoB:="23.07.1910"

FriendOne.PrintPerson

FriendTwo.PrintPerson

FriendOne.SayWhoIs

FriendTwo.SayWhoIs

'Связывание с двойниками.

'Теперь объекты могут реагировать на события!

FOne.Connect

End Sub

Public Sub Cars()

'Вызывается конструктор с параметрами

carOne.НоваяМашина "Антилопа", "12.12.12", "Неопределенный"

carTwo.НоваяМашина "Москвич", "12.11.98", "Морская волна"

carThree.НоваяМашина "Jeep", "23.05.97", "Orange"

End Sub

Public Sub CarOwners()

OwnerOne.ConnectOwnerAndCar FriendOne, carTwo

OwnerTwo.ConnectOwnerAndCar FriendThree, carOne

OwnerThree.InitCarOwner FN:="Юрий", LN:="Вегера", _

DoB:="21.08.34", Marka:="Газ69", DB:="20.01.76", Color:="Зеленый"

OwnerOne.PrintOwnerData

OwnerTwo.PrintOwnerData

OwnerThree.PrintOwnerData

End Sub

Public Sub CallEvents()

Dim DoB As Date

'Вызов методов приведет к возникновению событий!

'При замене фамилии возникнет событие ИзменениеФамилии

'Заметьте, не всегда фамилия будет изменена!

FriendOne.ВашаФамилия = "Фидотов"

FriendTwo.ВашаФамилия = "Волконская"

'При попытке узнать дату рождения

'может быть вызван обработчик события ДеньРождения.

DoB = FriendOne.ВашаДатаРождения

Debug.Print DoB

DoB = FriendTwo.ВашаДатаРождения

Debug.Print DoB

FriendOne.PrintPerson

FriendTwo.PrintPerson

'События не наследуются

Set FriendOne = OwnerTwo

'Нельзя связать теперь объект FriendOne с двойником

'FOne.Connect

FriendOne.ВашаФамилия = "Воробьянинов"

FriendOne.PrintPerson

End Sub

Public Sub Группа()

Const SizeGroup = 6

Const SizeGarage = 6

Dim i As Byte

Dim Group(1 To SizeGroup) As Личность

Dim Гараж(1 To SizeGarage) As Машина

Set Group(1) = FriendOne

Set Group(2) = FriendTwo

Set Group(3) = FriendThree

Set Group(4) = OwnerOne

Set Group(5) = OwnerTwo

Set Group(6) = OwnerThree

For i = 1 To SizeGroup

Group(i).SayWhoIs

Next i

Set Гараж(1) = carOne

Set Гараж(2) = carTwo

Set Гараж(3) = carThree

Set Гараж(4) = OwnerOne

Set Гараж(5) = OwnerTwo

Set Гараж(6) = OwnerThree

For i = 1 To SizeGarage

Гараж(i).PrintDataCar

Next i

End Sub

Public Sub ЛюдиИМашины()

Люди

Cars

CarOwners

Группа

PolyMorf FriendTwo

PolyMorf OwnerTwo

End Sub

Public Sub PolyMorf(One As Личность)

One.SayWhoIs

End Sub

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

Дадим теперь комментарии к этому тексту:

  1. В модуле Примеры вначале объявляются по три объекта классов Личность, Машина и ВладелецМашины. В методах Люди, Cars, CarOwners происходит инициализация этих объектов. Некоторые из этих личностей уже встречались в предыдущих примерах, но появился Остап Бендер и его знаменитая машина.

  2. Обратите внимание на создание объектов Owner класса ВладелецМашины, они создаются разными конструкторами.

  3. Основную работу выполняет метод Группа. Здесь создается массив элементов Group из трех объектов Friend и трех объектов Owner, принадлежащих разным классам. Тем не менее все эти объекты обрабатываются в едином цикле и для них вызывается метод SayWhoIs, который, как мы говорили ранее по-разному работает для объектов класса Личность и класса ВладелецМашины. Так что простой цикл по элементам Group демонстрирует реализацию полиморфизма.

  4. В методе Группа создана и продемонстрирована работа с еще одной группой элементов, - массивом Garage. Эту группу составляют объекты класса Машина и объекты класса ВладелецМашины. Обратите внимание, одни и те же объекты Owner входят в обе группы элементов и могут быть обработаны нужным образом.

  5. В процессе обработки массива Garage вызывается метод PrintDataCar, который унаследован объектами класса ВладелецМашины.

  6. В модуле Примеры приведена полиморфная функция PolyMorf(One As Личность), с формальным параметром родительского класса Личность. Она дважды вызывается в процедуре ЛюдиИМашины с фактическими параметрами разных классов.

  7. Процедура ЛюдиИМашины является процедурой, организующей всю работу, она поочередно запускает все перечисленные ранее процедуры. Сама она вызывается в обработчике события Click командной кнопки, встроенной в наш тестовый документ.

В процессе выполнения этой процедуры откроется серия диалоговых окон, где вначале будет сказано, кто такой Федотов и Катя, будет спрошено отчество Вегеры Юрия, затем опять будет рассказано о Федотове, Кате и Бендере, после чего появится информация о владельцах машин разных марок. На последнем этапе опять будет рассказано о Кате и владельце машины "Антилопа". Нам осталось привести результаты отладочной печати, появляющиеся при работе этой процедуры:

Станислав Федотов родился 21.05.39

Катя Павлова родилась 22.03.79

Станислав Федотов родился 21.05.39

владеет машиной:

Марка = Москвич

ДатаВыпуска = 12.11.98

Цвет = Морская волна

Остап Бендер родился 23.07.1910

владеет машиной:

Марка = Антилопа

ДатаВыпуска = 12.12.12

Цвет = Неопределенный

Юрий Алексеевич Вегера родился 21.08.34

владеет машиной:

Марка = Газ69

ДатаВыпуска = 20.01.76

Цвет = Зеленый

Марка = Антилопа

ДатаВыпуска = 12.12.12

Цвет = Неопределенный

Марка = Москвич

ДатаВыпуска = 12.11.98

Цвет = Морская волна

Марка = Jeep

ДатаВыпуска = 23.05.97

Цвет = Orange

Марка = Москвич

ДатаВыпуска = 12.11.98

Цвет = Морская волна

Марка = Антилопа

ДатаВыпуска = 12.12.12

Цвет = Неопределенный

Марка = Газ69

ДатаВыпуска = 20.01.76

Цвет = Зеленый

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

Как мы уже отмечали, родительский класс Личность реагирует на события. Это не мешает наследовать его интерфейсы, но не означает, что потомки будут наследовать события своего родителя. Чтобы убедиться, что зажигание событий не мешает работе потомков и не влияет на их работу, мы включили процедуру CallEvents. В процессе ее работы возникают события у объектов родительского класса и они правильно обрабатываются. Но, заметьте, после того как объект FriendOne был связан с объектом - потомком FriendOwner, при смене фамилии соответствующее событие уже не возникало, так что ничто не помешало Остапу Бендеру сменить свою фамилию. По ходу работы этой процедуры в появляющихся диалоговых окнах будет сообщено об отказе смены фамилии Федотову и появится поздравление Кате Павловой в связи с замужеством. Приведем результаты отладочной печати при работе этой процедуры:

21.05.39

22.03.79

Станислав Федотов родился 21.05.39

Катя Волконская родилась 22.03.79

Остап Воробьянинов родился 23.07.1910

Этот пример демонстрирует основные возможности работы с семейством классов, появившиеся в связи с введением механизма наследования

Создание динамических структур данных

Говоря об объектах, мы не раз отмечали, что необходимо уметь работать не только с отдельными объектами, но и группами этих объектов. Конечно, можно во многих случаях использовать массив для представления группы объектов. Однако для решения многих, возникающих в программировании задач, необходимы более гибкие динамические структуры данных, позволяющие организовать сложные связи между элементами таких структур. Примеры таких структур хорошо известны, - это, например, списки, линейные и нелинейные, стеки, деки и очереди, деревья бинарные и сбалансированные. В современных языках программирования некоторые из таких структур стали такой же частью языка, как и массивы. Реализуется такая динамическая структура чаще всего в виде класса. Прекрасным примером является реализация самой системы Office 2000. Как мы не раз говорили, Office 2000 можно рассматривать как семейство классов объектов. Так вот, почти для каждого класса объектов, существует и класс, задающий коллекцию этих объектов. Классы - коллекции составляют почти половину классов Office 2000. Все они устроены похожим образом и имеют некоторый стандартный набор методов, позволяющих удалить или добавить новый элемент в коллекцию, получить элемент из коллекции, зная его порядковый номер или ключ элемента. Некоторые коллекции имеют специфические свойства и поведение, обусловленное спецификой самих элементов, хранящихся в коллекции. В ряде случаев, коллекции могут допускать хранение элементов разных классов. Обилие коллекций в Office 2000 первоначально раздражает, поскольку хотелось бы иметь единый класс со свойствами и методами, не зависящими от природы элементов, составляющих коллекцию. Но со временем ко всему привыкаешь и начинаешь принимать как должное, что у каждого класса объектов своя коллекция. Благодаря подсказкам по ходу написания программы и легко доступной справочной системе, не требуется держать в памяти специфику каждой коллекции.

Частью языка VBA является класс Collection. Он существенно облегчает работу с динамическими структурами данных во многих типичных ситуациях. Он позволяет хранить в коллекции данные разных типов и имеет хорошо продуманные свойства и методы. Не менее важно и то, что VBA позволяет создавать и собственные динамические структуры данных сколь угодно сложно организованные. К их рассмотрению мы сейчас и приступаем.

Встроенный динамический класс Collection

Коллекция в VBA - упорядоченная совокупность элементов, вообще говоря, разного типа. Этим коллекция отличается от массива, где объединяются только однотипные элементы. Все элементы индексированы, но некоторые могут иметь и ключ, связанный с элементом. Размер коллекции заранее не фиксируется и может динамически изменяться. Любой существующий элемент коллекции может быть удален, при этом не возникает "дыр" - элементы перенумеровываются, и непрерывность последовательности индексов не нарушается. Неприятным следствием этого факта, приводящего иногда к ошибке, является то, что индекс в отличие от ключа не является постоянной характеристикой элемента и может изменяться в процессе работы с коллекцией. Новый элемент может быть добавлен в произвольное место коллекции, - как перед некоторым элементом, так и после любого из элементов.

У класса Collection одно свойство - Count и 3 метода: Add, Item, Remove. Рассмотрим их подробнее:

  1. Свойство Count возвращает число элементов коллекции. Доступно только для чтения, имеет тип возвращаемого значения Long.

  2. Метод Add (item, key, before, after) добавляет элементы в коллекцию. Первый параметр Item является обязательным и задает добавляемый элемент. Параметр key - необязателен, он задается, когда элементу ставится в соответствие ключ. Два последних необязательных параметра уточняют позицию вставки, - задают индекс или ключ элемента, перед или после которого добавляется новый элемент. Только один из этих параметров может быть задан. Если не задан ни один, элемент добавляется в конец коллекции.

  3. Метод Remove(key) удаляет элементы коллекции. Удаляется элемент с заданным ключом: заметьте, это может быть индекс элемента. После удаления происходит перенумерация элементов и уменьшается счетчик Count.

  4. Метод Item(key) возвращает значение элемента списка с заданным ключом. И здесь в роли ключа может выступать обычный индекс элемента.

Обратите внимание на мощность методов класса. Они позволяют реализовать различные классические динамические структуры. Конечно же, совсем просто реализуется обычный односвязный список с возможностью добавления элементов в начало или конец списка. Но можно реализовать и значительно более мощную структуру, называемую словарем. Словарь представляет собой связанную совокупность пар элементов. Первый элемент пары называется ключом, второй - информационным полем. Особенностью словарей является то, что, зная ключ элемента, можно получить доступ к информационному полю. При этом, обратите внимание, в классе Collection на ключ не накладывается никаких ограничений, - это обычная строка. Немаловажно, что есть и альтернативный способ прямого доступа к элементам коллекции по индексу, когда в качестве ключа выступает порядковый номер элемента в коллекции. Таким образом, коллекция соединяет в себе достоинства списков и массивов.

Приведем теперь пример процедуры, подробнее демонстрирующий работу с коллекцией. Наша коллекция будет включать данные двух типов: целочисленные и строковые. Часть элементов будет иметь ключ, остальные - только индекс. Элементы будут добавляться в заданную позицию и удаляться. Отладочная печать позволит проследить за этим процессом:

Sub TestOfCollection()

'Так объявляются объекты (переменные) типа Collection

Dim MyCollection As New Collection

'Объявление обычных локальных переменных

Dim i As Integer

Dim N As Long

'Оператор With позволяет избежать многократного указания имени объекта

With MyCollection

N =.Count

Debug.Print" Число элементов пустой коллекции =", N

' Добавление элементов в конец списка.

'Элементы имеют индексы, но не имеют ключа.

.Add (2)

.Add (4)

.Add (6)

'Добавление нечетных элементов на свои места.

'Заметьте, как указывается позиция

'добавления c использованием параметров - before и after

' Добавляемые элементы имеют строковый тип и обладают ключом

.Add" один"," first", 1 ' before (перед первым элементом)

.Add" три"," third",, 2 'after (после второго)

.Add" пять"," fifth",, 4

N =.Count

Debug.Print" Число элементов после 6-и вызовов метода Add", N

Debug.Print" Элементы коллекции:"

' Отладочная печать созданной коллекции из шести элементов.

For i = 1 To MyCollection.Count

Debug.Print MyCollection(i)

Next

' Удаление 4-го и 5-го элементов по заданному индексу и ключу.

.Remove 4

.Remove" fifth"

N =.Count

Debug.Print" Число элементов после двух вызовов метода Remove=", N

Debug.Print" Элементы коллекции:"

'И снова печать коллекции, в которой теперь четыре элемента.

For i = 1 To MyCollection.Count

Debug.Print MyCollection(i)

Next

End With

End Sub

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

Приведем теперь результаты отладочной печати:

Число элементов пустой коллекции = 0

Число элементов после 6-и вызовов метода Add = 6

Элементы коллекции: один 2 три 4 пять 6

Число элементов после двух вызовов метода Remove = 4

Элементы коллекции: один 2 три 6

Подчеркнем еще раз основные свойства класса Collection:

  1. Класс позволяет объединять в коллекцию элементы разных типов, хотя чаще применяются однотипные коллекции.

  2. Класс объединяет в себе свойства линейного списка, динамического массива и структуры, называемой словарем , или отображением (map).

  3. Это список, поскольку определена операция Add, позволяющая динамически добавлять элементы в конец списка.

  4. Это динамический массив, поскольку все элементы индексированы и к ним возможен прямой доступ по индексу. С другой стороны, размер массива не фиксируется и динамически изменяется при добавлении и удалении элементов.

  5. Это словарь, поскольку добавляемые элементы могут иметь ключ. Прямой доступ к элементам возможен как по индексу, так и по ключу. Под "прямым" здесь понимается доступ, основанный на применении функций расстановки (хэширования). Конкретный вид этих функций, определяющий эффективность поиска, - "секрет фирмы".

  6. В классе определены методы Add, Item, Remove и свойство Count.

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

Public Sub Collection()

'Создание и работа с коллекцией личностей

Dim Личности As New Collection

'Работа с коллекцией, как со списком

Dim Адам As New Личность

Адам.InitPerson "Адам", "Первый Человек", #1/1/100#

Личности.Add Адам

Dim Ной As New Личность

Ной.InitPerson "Ной", "Праведник", #1/1/100#

Личности.Add Ной

'Работа с коллекцией, как с динамическим массивом

Dim Шекспир As New Личность

Шекспир.InitPerson "Вильям", "Шекспир", #4/23/1564#

Личности.Add Item:=Шекспир, After:=2

Dim Гомер As New Личность

Гомер.InitPerson "Гомер", "Великий Слепой", #1/1/100#

Личности.Add Item:=Гомер, Before:=3

Личности(4).SayWhoIs

'Работа с коллекцией, как со словарем

Dim Пушкин As New Личность

Пушкин.InitPerson "Александр", "Пушкин", #6/6/1799#

Личности.Add Item:=Пушкин, Key:="Гений"

Dim Булгаков As New Личность

Булгаков.InitPerson "Михаил", "Булгаков", #1/23/1891#

Личности.Add Item:=Булгаков, Key:="Мастер"

Debug.Print Личности("Гений").ВашаФамилия, " - это Гений!"

Debug.Print Личности("Мастер").ВашаФамилия, " - это Мастер!"

'Печать всего списка

Dim I As Byte

For I = 1 To Личности.Count

Личности(I).PrintPerson

Next I

End Sub

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

В процессе работы этой процедуры в диалоговом окне появится сообщение о Шекспире, а в отладочном окне Immediate появятся следующие результаты:

Пушкин - это Гений!

Булгаков - это Мастер!

Адам Первый Человек родился 01.01.100

Ной Праведник родился 01.01.100

Гомер Великий Слепой родился 01.01.100

Вильям Шекспир родился 23.04.1564

Александр Пушкин родился 06.06.1799

Михаил Булгаков родился 23.01.1891

При создании коллекции мы использовали все три возможности добавления элементов: с заданным ключом, с заданным индексом и в конец списка. Доступ к элементам осуществлялся либо по индексу, либо по ключу. Так что наш пример демонстрирует все достоинства работы с классом Collection. Но, говоря о достоинствах, не следует забывать и о недостатках. Заметьте: при работе с коллекцией потребовалось для каждой личности создать собственную переменную, так что, по существу, мы имеем копии всех элементов коллекции в виде переменных. Это связано с тем, что при добавлении элемента в коллекцию не создается копия элемента, а используется ссылка на существующий элемент, так что коллекция не имеет собственной памяти для хранения элементов. Позже мы покажем, как можно преодолеть этот недостаток коллекции, а пока же подчеркнем, что по этой причине и по многим другим следует уметь создавать собственные динамические структуры данных. К их рассмотрению мы и переходим.