Тема 2.6 Объектно-ориентированное программирование в VBA
VBA представляет средства для использования имеющихся и создания новых объектов. Класс — это общее описание однородных по структуре объектов. Класс задает характеристики и поведение объектов. Классы в VBA оформляются в виде отдельных модулей.
Объявление пользовательских классов
Концептуально, создание класса начинается с этапа проектирования, где определяются свойства и методы, которыми должны обладать объекты нового класса.
Рассмотрим следующий пример: пусть требуется создать класс, описывающий студента. Объект такого класса может представлять в виде свойств такую информацию о студенте, как его имя, отчество и фамилию, дату и место рождения, контактную информацию, пол, паспортные данные и т.п. В качестве методов можно указать возможность редактирования информации, возможность полного или, наоборот, частичного отображения информации о студенте. Семантически такое описание может быть представлено, например, следующим образом:
// псевдокод описания объекта Студент Студент < Фамилия: строка Имя: строка Отчество: строка Дата_рождения: Дата Пол: символьный или логический Контактная_информация: строка >Студент.Полное_имя: строка, только чтение Студент.Полное_описание: строка, только чтение Студент.Править_описание (Нов_Фамилия, Нов_Имя, Нов_Отчество, Нов_Дата_рожд, _ Нов_Пол, Нов_Конт_Инф)
' Закрытые члены класса, прямой доступ к ним невозможен - ' только через свойства Private fLastName As String ' фамилия Private fFirstName As String ' имя Private fMiddleName As String ' отчество Private fBirthDay As Date ' дата рождения Private fGender As String * 3 ' пол Private fContacts As String ' адрес и телефон ' Конструктор класса. Вызывается в момент создания объектной переменной Private Sub Class_Initialize() fLastName = "Фамилия не указана" fFirstName = "Имя не указано" fMiddleName = "Отчество не указано" fContacts = "Адрес не указан" End Sub ' Свойства для чтения Public Property Get LastName() As String LastName = fLastName End Property Public Property Get FirstName() As String FirstName = fFirstName End Property Public Property Get MiddleName() As String MiddleName = fMiddleName End Property Public Property Get BirthDay() As Date BirthDay = fBirthDay End Property Public Property Get Gender() As String Gender = fGender End Property Public Property Get Contacts() As String Contacts = fContacts End Property ' Свойства для записи Public Property Let LastName(ByVal NewValue As String) fLastName = NewValue End Property Public Property Let FirstName(ByVal NewValue As String) fFirstName = NewValue End Property Public Property Let MiddleName(ByVal NewValue As String) fMiddleName = NewValue End Property Public Property Let BirthDay(ByVal NewValue As Date) fBirthDay = NewValue End Property Public Property Let Gender(ByVal NewValue As String) fGender = NewValue End Property Public Property Let Contacts(ByVal NewValue As String) fContacts = NewValue End Property ' Свойства ТОЛЬКО ДЛЯ ЧТЕНИЯ (нет парных Property Let) Public Property Get FullName() As String FullName = fLastName & " " & fFirstName & " " & fMiddleName End Property Public Property Get FullInfo() As String FullInfo = fLastName & Chr(9) & fFirstName & Chr(9) & fMiddleName & Chr(9) _ & CStr(fBirthDay) & Chr(9) & fGender & Chr(9) & fContacts End Property ' Метод для изменения свойств объекта. ' Все параметры объявлены как необязательные (Optional). ' Это позволяет изменять только необходимые поля класса. ' Изменять поля можно и через соответствующие свойства для записи (Property Let), ' этот метод приведен для примера Public Sub EditInfo(Optional LastName As String, Optional FirsName As String, _ Optional MiddleName As String, Optional BirthDay As Date, _ Optional Gender As String, Optional Contacts As String) fLastName = LastName fFirstName = FirstName fMiddleName = MiddleName fBirthDay = BirthDay fGender = Gender fContacts = Contacts End Sub
- Синтаксис описания членов класса такой же, как и для обычных переменных. Использование Private позволяет ограничить доступ к членам класса из других модулей и, тем самым, обеспечить целостность данных.
- Конструктор Class_Initialize предназначен для задания начальных значений переменным — членам класса и выполнения других операций инициализации. Он вызывается автоматически — в момент создания экземпляра класса.
- Свойства класса объявляются с ключевым словом Property. При этом функция Property Get создает свойство для чтения, а процедура Property Let служит для записи значений в свойства базовых типов (в т.ч. массивов и пользовательских типов). Процедура Property Set служит для присваивания значений членам объектного типа (см. листинг 25). Общий синтаксис объявления свойств:
' для чтения [Public | Private] [Static] Property Get [()] [As ] имяФункции = возвращаемое значение [Exit Property] имяФункции = возвращаемое значение End Property ' для записи [Public | Private] [Static] Property Let [()] [Exit Property] End Property ' для работы с объектными членами класса [Public | Private] [Static] Property Set [()] [Exit Property] End Property
' ---------------------------------------------- ' Модуль класса CFaculty - объект "Факультет" (приведен фрагмент кода) ' ---------------------------------------------- Private fTitle As String ' Название факультета Public Property Get Title() As String Title = fTitle End Property Public Property Let Title(NewTitle As String) fTitle = NewTitle End Property . ' ---------------------------------------------- ' Модуль класса CGroup - объект "Учебная группа" (приведен фрагмент кода) ' ---------------------------------------------- ' Встраивание объектных членов класса Private fFaculty As New CFaculty Dim fStudents() As New CStudent . ' Использование Property Set для задания значения объектному члену Public Property Set Faculty(Title) Set fFaculty = Title End Property ' Чтение названия факультета Public Property Get Faculty() As String Faculty = fFaculty.Title End Property .
Создание объектных переменных
- явным указанием класса объекта;
- ссылкой на ранее созданный объект.
- При раннем связывании в момент объявления указывается класс объекта:
Private | Public | Dim As New
Public Faculty As New CFaculty Private Groups(3) As New CGroup Dim stud As New CStudent
Использование раннего связывания имеет одно преимущество: явное указание класса позволяет получить доступ к его свойствам и методам уже на этапе разработки в VBE. Это выражается в том, что при введении имени объектной переменной появляется всплывающий список доступных операций над объектом.
Использование объектов
. = значение ' запись свойства
Для обращения к объектным свойствам следует использовать ключевое слово Set. Вызов методов и передача параметров аналогичны работе с обычными процедурами и функциями. Примеры работы с экземплярами созданных классов — в листинге 26.
Листинг 26. Работа с объектами
' ------------------------------------------------------------------ ' Создание экземпляра класса и работа с его свойствами и методами ' ------------------------------------------------------------------ Sub sample30() Dim stud As New CStudent ' экземпляр класса CStudent ' Обращения к свойствам объекта stud.FirstName = "Иван" stud.LastName = "Петров" stud.Contacts = "г.Омск, пр.Мира, 11, к.8. т/ф (3812) 65-96-11" End Sub
Тема 5.3. Средства объектно-ориентированного программирования в Visual Basic
5.3.1. Две роли классов в ооп и типы данных в Visual Basic
Язык программирования Visual Basic является объектно-ориентированным языком. Это означает, что все функциональные части приложения рассматриваются как объекты, содержащие в себе некоторые свойства, способные выполнять определенные методы и генерировать события.
С классами студенты сталкивались практически во всех предыдущих темах. Это были классы, предоставленные пользователю VS .Net в виде библиотек классов .Net Framework.
Например, класс математических функций – System.Math, класс – System.Array, System.IO, форма и элементы управления – System.Form и другие.
Объектно-ориентированное программирование и проектирование построено на классах. Любую программную систему, построенную в объектном стиле, можно рассматривать как совокупность классов, возможно объединенных в проекты, пространства имен, решения, как это делается при программировании в Visual Studio .Net.
Очень важно обратить внимание на то, что у класса две различные роли: модуляитипа данных.
Во-первых, класс – это модуль, архитектурная единица построения программной системы. Модульность построения – основное свойство программных систем. ВООПпрограммная система, строящаяся по модульному принципу, состоит из классов, являющихся основным видом модуля. Модуль может не представлять собой содержательную единицу, его размер и содержание определяется архитектурными соображениями, а не семантическими. Ничто не мешает построить монолитную систему, состоящую из одного модуля, – она может решать ту же задачу, что и система, состоящая из многих модулей.
Вторая роль класса не менее важна. Класс – это тип данных, задающий реализацию некоторой абстракции данных, характерной для задачи, в интересах которой создается программная система. С этих позиций классы, это не просто кирпичики, из которых строится система. Каждый кирпичик теперь имеет важную содержательную начинку. Представьте себе современный дом, построенный из кирпичей, и дом будущего, где каждый кирпич выполняет определенную функцию, один следит за температурой, другой – за составом воздуха в доме. Объектно-ориентированная программная система напоминает дом будущего.
Состав класса, его размер определяется не архитектурными соображениями, а той абстракцией данных, которую должен реализовать класс. Если создается класс Account, реализующий такую абстракцию как банковский счет, то в этот класс нельзя добавить поля из классаCar, задающего автомобиль.
Объектно-ориентированная разработка программной системы основана на стиле, называемом проектированием от данных. Проектирование системы сводится к поиску подходящих для данной задачи абстракций данных. Каждая из них реализуется в виде класса, которые и становятся модулями – архитектурными единицами построения нашей системы. В основе класса лежит абстрактный тип данных.
В хорошо спроектированной объектно-ориентированной системе каждый класс играет обе роли, так что каждый модуль нашей системы имеет вполне определенную смысловую нагрузку. Типичная ошибка – рассматривать класс, только как архитектурную единицу, объединяя под обложкой класса разнородные поля и функции, после чего становится неясным, какой же тип данных задает этот класс.
Напомним, что типы данных могут быть двух видов. Тип данных является типом значений, если он содержит данные в пределах своей собственной области памяти. Ссылочный тип содержит указатель на другую область памяти, содержащую данные.
К типам значения относятся:
- все числовые типы данных;
- Boolean, Char и Date;
- все структуры, даже если их члены являются ссылочными типами;
- перечисления, поскольку их базовый тип всегда является SByte, Short, Integer Long, Byte, UShort, UInteger или ULong.
- String;
- все массивы, даже если их члены являются типами значений;
- типы классов, например Form;
- делегаты.
- пространства имен;
- модули;
- события;
- свойства и процедуры;
- переменные, константы и поля.