Когда использовать класс в VBA? - PullRequest
38 голосов
/ 23 сентября 2008

Когда целесообразно использовать класс в Visual Basic для приложений (VBA)?

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

Ответы [ 11 ]

50 голосов
/ 27 сентября 2008

Это зависит от того, кто собирается разрабатывать и поддерживать код. Типичные авторы макросов «Опытный пользователь», взламывающие небольшие специальные приложения, могут быть смущены использованием классов. Но для серьезного развития причины использования классов такие же, как и в других языках. У вас те же ограничения, что и у VB6 - без наследования - но вы можете иметь полиморфизм с помощью интерфейсов.

Хорошо использовать классы для представления сущностей и коллекций сущностей. Например, я часто вижу код VBA, который копирует диапазон Excel в двумерный массив, а затем манипулирует двумерным массивом с помощью кода:

Total = 0
For i = 0 To NumRows-1
    Total = Total + (OrderArray(i,1) * OrderArray(i,3))
Next i

Более читабельно копировать диапазон в коллекцию объектов с соответствующими именами, что-то вроде:

Total = 0
For Each objOrder in colOrders
    Total = Total + objOrder.Quantity * objOrder.Price
Next i

Другим примером является использование классов для реализации шаблона проектирования RAII (Google для него). Например, одна вещь, которая мне может понадобиться, это снять защиту листа, выполнить некоторые манипуляции, а затем снова защитить его. Использование класса гарантирует, что лист всегда будет снова защищен, даже если в вашем коде произойдет ошибка:

--- WorksheetProtector class module ---

Private m_objWorksheet As Worksheet
Private m_sPassword As String

Public Sub Unprotect(Worksheet As Worksheet, Password As String)
    ' Nothing to do if we didn't define a password for the worksheet
    If Len(Password) = 0 Then Exit Sub

    ' If the worksheet is already unprotected, nothing to do
    If Not Worksheet.ProtectContents Then Exit Sub

    ' Unprotect the worksheet
    Worksheet.Unprotect Password

    ' Remember the worksheet and password so we can protect again
    Set m_objWorksheet = Worksheet
    m_sPassword = Password
End Sub

Public Sub Protect()
    ' Protects the worksheet with the same password used to unprotect it
    If m_objWorksheet Is Nothing Then Exit Sub
    If Len(m_sPassword) = 0 Then Exit Sub

    ' If the worksheet is already protected, nothing to do
    If m_objWorksheet.ProtectContents Then Exit Sub

    m_objWorksheet.Protect m_sPassword
    Set m_objWorksheet = Nothing
    m_sPassword = ""
End Sub

Private Sub Class_Terminate()
    ' Reprotect the worksheet when this object goes out of scope
    On Error Resume Next
    Protect
End Sub

Затем вы можете использовать это для упрощения вашего кода:

Public Sub DoSomething()
   Dim objWorksheetProtector as WorksheetProtector
   Set objWorksheetProtector = New WorksheetProtector
   objWorksheetProtector.Unprotect myWorksheet, myPassword

   ... manipulate myWorksheet - may raise an error

End Sub 

При выходе из этой подпрограммы objWorksheetProtector выходит из области действия, и рабочая таблица снова защищается.

8 голосов
/ 25 сентября 2008

Я думаю, что критерии совпадают с другими языками

Если вам нужно связать вместе несколько фрагментов данных и некоторые методы, а также конкретно обработать то, что происходит, когда объект создается / завершается, классы идеальны

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

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

Затем можно добавить объект индикатора выполнения с методами, чтобы открывать и закрывать его и отображать имена текущего действия, а также время в мс и возможное оставшееся время на основе предыдущих сохраненных отчетов и т. Д.

Другим примером может быть, если вам не нравится мусор в группе пользователей Access, вы можете создать свой собственный класс User с методами входа и выхода и функциями для контроля доступа пользователей на уровне группы / аудита / регистрации определенных действий / ошибок отслеживания и т. Д.

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

Вы рано или поздно приближаетесь к пределам VBA, но это довольно мощный язык, и если ваша компания связывает вас с ним, вы действительно можете получить некоторые хорошие, сложные решения.

5 голосов
/ 13 февраля 2012

Классы чрезвычайно полезны при работе с более сложными функциями API, особенно когда им требуется структура данных.

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

Мне нравится оборачивать структуру (UDT) и объявления функций API в класс CfileDialog. Событие Class_Initialize устанавливает значения по умолчанию для членов структуры, так что когда я использую класс, мне нужно только установить элементы, которые я хочу изменить (через процедуры Property). Константы флагов реализованы как Enum. Так, например, чтобы выбрать электронную таблицу для открытия, мой код может выглядеть следующим образом:

Dim strFileName As String
Dim dlgXLS As New CFileDialog

With dlgXLS
  .Title = "Choose a Spreadsheet"
  .Filter = "Excel (*.xls)|*.xls|All Files (*.*)|*.*"
  .Flags = ofnFileMustExist OR ofnExplorer

  If OpenFileDialog() Then
    strFileName = .FileName
  End If
End With
Set dlgXLS = Nothing

Класс устанавливает каталог по умолчанию в Мои документы, хотя при желании я могу изменить его с помощью свойства InitDir.

Это только один пример того, как класс может быть чрезвычайно полезным в приложении VBA.

5 голосов
/ 23 сентября 2008

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

Это не значит, что один не смог найти полезное место для класса в VBA или сделать совершенно полезные вещи с помощью класса, просто я никогда не находил их полезными в этой среде.

3 голосов
/ 24 сентября 2008

Вы также можете повторно использовать код VBA без использования реальных классов. Например, если у вас есть вызываемый, VBACode. Вы можете получить доступ к любой функции или подразделу в любом модуле со следующим синтаксисом:

VBCode.mysub(param1, param2)

Если вы создаете ссылку на шаблон / документ (как в случае с dll), вы можете ссылаться на код из других проектов таким же образом.

2 голосов
/ 13 февраля 2012

Я использую классы, если я хочу создать самоинкапсулированный пакет кода, который я буду использовать во многих проектах VBA, которые встречаются для различных клиентов.

2 голосов
/ 13 июня 2009

Я использую классы, когда мне нужно что-то сделать, и класс сделает это лучше всего :) Например, если вам нужно реагировать на (или перехватывать) события, вам нужен класс. Некоторые люди ненавидят UDT (определяемые пользователем типы), но они мне нравятся, поэтому я использую их, если я хочу простой документирующий код на английском языке. Pharmacy.NCPDP намного легче читать, чем strPhrmNum :) Но UDT ограничен, так что я хочу иметь возможность установить Pharmacy.NCPDP и заполнить все остальные свойства. И я также хочу сделать это, чтобы вы не могли случайно изменить данные. Тогда мне нужен класс, потому что у вас нет свойств только для чтения в UDT и т. Д.

Еще одно соображение - просто читаемость. Если вы работаете со сложными структурами данных, часто полезно знать, что вам просто нужно позвонить в Company.Owner.Phone.AreaCode и попытаться отследить, где все структурировано. Особенно для людей, которым нужно поддерживать эту кодовую базу через 2 года после вашего ухода:)

Мои два цента - это «Код с целью». Не используйте класс без причины. Но если у вас есть причина, то сделайте это:)

2 голосов
/ 12 июня 2009

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

(Я не знаю, почему люди не торгуют наборами библиотек спецификации для VBA. Может быть, инструменты XML изменили ситуацию.)

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

2 голосов
/ 25 сентября 2008

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

0 голосов
/ 03 августа 2017

Вы можете определить класс оболочки SQL в доступе, который более удобен, чем наборы записей и querydefs. Например, если вы хотите обновить таблицу на основе критериев в другой связанной таблице, вы не можете использовать объединения. Вы могли бы создать набор записей vba и querydef, чтобы сделать это, однако мне легче с классом. Кроме того, ваше приложение может иметь некоторую концепцию, которая требует более двух таблиц, поэтому лучше использовать imo для этого. Например. Вы приложение отслеживает инциденты. Инцидент имеет несколько атрибутов, которые будут храниться в нескольких таблицах {пользователи и их контакты или профили, описание инцидента; отслеживание статуса; Контрольные списки, чтобы помочь сотруднику службы поддержки ответить на инцидент; Ответить ...} . Чтобы отслеживать все связанные запросы и отношения, нам может помочь oop. Это облегчение, чтобы иметь возможность делать Incident.Update (xxx) вместо всей кодировки ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...