Шрифт:
Объявления модулей в clsApplication выглядят так:
Private WithEvents mf_Parent As nidiManager
Private WithEvents mo_Projects As clsProjects
Private WithEvents mo_Tasks As clsTasks
Private WithEvents mo_Today As clsToday
Private WithEvents mo_Archive As clsArchive
Private mo_Contacts As clsContacts
Private mo_DataService As clsDataService
Private mo_Reports As clsReports
Private mo_ProgConfig As clsProgConfig
Private mo_PickList As clsPickList
Private mc_Tasks As New Collection '–коллекция объектов clsTasks
Private mc_Projects As New Collection '–коллекция объектов clsProjects
Private mc_Sources As New Collection '–коллекция объектов clsSource
Private moJJser As clsUser
Private mo_Source As clsSource
Private ms_DSN As String 'применяется при подключении
Здесь, если не считать нехватки комментариев уровня модуля, присутствуют все дочерние объекты clsApplication. Из этого фрагмента кода в принципе можно вывести всю объектную иерархию программы.
Реализация в программе многочисленных событий заметно «стройнит» код форм. В большинстве случаев родителями форм выступают модули классов, причем имена форм явственно свидетельствуют об этих отношениях. К примеру, clsProjects запускает frmProjects; впоследствии, если в форме происходит какое-то событие, его аналог сразу запускается в родительском элементе управления. Таким образом, код по большей части локализуется, что, в свою очередь, способствует инкапсуляции.
Все содержащиеся в программе основные объекты (clsTasks, clsProjects и clsToday) обращаются к локальной копии объекта-источника данных под именем clsData Provider. Это модуль класса VB, в котором поведение источника данных приравнено к значению vbDataSource. Объект clsDataProvider пользуется услугами посредника clsDataService, причем посреднические обязанности осуществляются через функцию под именем GetDataProviderRS, которая одним своим именем демонстрирует факт извлечения набора записей источника данных. Здесь же расположено большинство управляющих программой SQL-операторов. Наконец, приставка «Get» указывает на действие и в некоторой степени объясняет назначение процедуры. По-моему, я уже достаточно пожурил свою живность насчет нехватки комментариев, так что об этом недостатке я больше говорить не буду.
С точки зрения доступа к данным объект clsDataService является открытым интерфейсом логического звена данных. Объект clsDataProvider, описанный в предыдущем абзаце, обеспечивает взаимодействие между данными и уровнем графического пользовательского интерфейса. В составе clsDataService есть дочерний объект под именем clsDataAccess, который фактически осуществляет подключение к базе данных и исполняет передаваемые родительским объектом SQL-операторы. Подобного рода разделение обслуживания сводит взаимозависимость к минимуму и, по моему мнению, существенно облегчает сопровождение и модернизацию электронного администратора.
Другие достоинства и недостатки
По существу, я лишь мельком коснулся некоторых аспектов, которые можно было бы проверить на этом примере. Далее я затрону еще пару вопросов, которые могут вам пригодиться при проверке собственного кода.
Соединение с базой данных устанавливается в начале исполнения, поддерживается в активном состоянии и по мере необходимости передается нуждающимся в данных объектам. Эта схема вполне приемлема для двухзвенной программы с одним пользователем. В то же время, если мы попытаемся масштабировать мою программу для нескольких пользователей, окажется, что обозначенное проектное решение не слишком удачно. Причина, по которой я к нему обратился, заключается в том, что его можно было удобно и быстро реализовать. Оправдывают ли эти преимущества принятые решения? В принципе, мне этого хватает, поскольку расширять свою программу я не собираюсь. С другой стороны, это наглядный пример принятия под давлением временных ограничений простейшего решения, о котором впоследствии можно сильно пожалеть.
Динамические наборы записей открываются в каждом объекте по отдельности и, подобно соединению с базой данных, поддерживаются в активном состоянии. Такое решение повышает реактивность программы, если с ней на одной физической машине работает один пользователь, но сильно ухудшает шансы на масштабирование. Бессвязные наборы записей в данном случае могли бы существенно улучшить возможности масштабирования программы.
Нехватка связей между таблицами – это еще один очевидный недостаток кода, связанный с наборами записей. Иначе говоря, вместо того чтобы задать ссылку внешним ключом на таблицу проектов, я сохраняю имя проекта в таблице заданий. Таким образом, я полностью исключаю возможность переименования проектов.
Плохой код и безмозглый кот! И, опять же, пожертвовав здесь значительно более оптимальным решением, я предпочел завершить кодирование побыстрее. Впрочем, в защиту выбранного решения выступает и то обстоятельство, что процесс генерации отчетов с помощью программы Crystal Reports при передаче в файл-шаблон ненормализированного набора записей значительно упростился. Кроме того, так мне стало удобнее разрабатывать сам шаблон – ведь, работая в программе Crystal Designer, я просто открывал базу данных и копировал в шаблон ее поля.
Конечно, можно было бы подумать и над другими решениями, но то, на котором я остановился, по крайней мере, позволило оперативно генерировать для подведомственной мне группы еженедельные отчеты.
Нет. Поскольку мне хотелось сделать программу удобочитаемой, я в основном отдавал предпочтение закрытым и открытым перечислимым типам (перечислимые типы с глобальной областью действия присутствуют в basMain). Есть все же несколько массивов элементов управления, на которых вместо перечислимого типа установлена числовая ссылка. Но в основном, чтобы понять назначение параметра, достаточно взглянуть на его определение.
141
Волшебными я называю числа, которые внезапно начинают играть серьезную роль, – по той лишь причине, что найти определение их значений мне не удается.