Изменить стиль страницы

Следовал ли я стандартам?

В основном я следовал стандартам – по крайней мере, мне так кажется. VB я пользуюсь, начиная с версии 1.0, и с годами отношения с кодом складывались у меня (наверное, так же как и у вас) по-разному – был и удачный, и провальный опыт. С моей точки зрения, следование стандартам VB выражается в попытках привести объектно-ориентированные понятия в соответствие с этим языком, который, по правде говоря, отнюдь не полностью поддерживает объектно-ориентированную парадигму.

В главе 4 я изложил понятие задачи, или задания, – основного организующего принципа программного обеспечения. Просмотрев мой код, вы найдете в нем объект под именем clsTasks и вспомогательный объект clsTask. В этих двух модулях классов инкапсулированы пользовательское взаимодействие и все данные, обрабатываемые программой в связи с заданиями. Формы frmTask и frmTasks, ответственные за обработку заданий на стороне графического пользовательского интерфейса, являются дочерними объектами объекта clsTasks. Все прочие объекты, например clsToday, при обработке заданий обращаются к локальным экземплярам clsTasks. Эта схема довольно удачно, как мне кажется, иллюстрирует методику многократного использования объектов.

Модульные объявления объекта clsTasks выглядят так:

'-Закрытые объекты и события

Private mo_DataService As clsDataService '–данные объекта

Private mo_PickList As clsPickList '–список отбора для форм

Private WithEvents mfjasks As frmTasks '–все задания, связанные с frmTasks

Private WithEvents mfjask As frmTask '–отдельное задание, связанное с frmTask

Private mo_DataGrid As DataGrid

Private WithEvents mo_DataProvider As clsDataProvider '–основные данные

Private ml_CurTaskID As Long '–выбранный идентификатор задания

Private ms_Project As String '–применяется с frmProject

Private mo_ProgConfig As clsProgConfig

Private ms_TaskFilter As String

Private mo_Task As clsTask

Private mb_NeedRefresh As Boolean

Private ms_Resource As String

Private ms_Source As String '–открытые объекты и события

Public Event TaskUpdatedO

И что мы имеем? Много комментариев, среди которых нет ни одного, который описывал бы назначение центрального объекта. Плохой код и бездарный кот! И каким же образом человек со стороны сможет понять, зачем этот объект нужен, если нет никаких описаний?! Для этого придется основательно изучать код. Я-то его знаю вдоль и поперек, а вот свежий взгляд наткнется на труднопреодолимое препятствие.

Будь вы менеджером, вы бы, конечно, настояли на введении заголовка модуля с указанием его автора и даты создания. Кроме того, вы, вероятно, потребовали бы от программиста составить обзор модуля, обозначив в нем имена открытых процедур и механизм «жизнеобеспечения» ими объекта.

Нельзя, однако же, не признать некоторые достоинства вышеприведенного фрагмента кода. Обратите внимание на имена переменных – m в них идентифицирует область действия (модуль), а следующий символ обозначает тип переменной (Соответствует длинной переменной, s – строковой, b – логической, и т. д.).

Теперь рассмотрим конкретную процедуру, инициирующую процесс отображения формы задания:

Public Sub Show(Optional sResource As String ="")

If (mf_Tasks Is Nothing) Then

SetHourglass

Set mf_Tasks = New frmTasks Load mfjasks

Set mo_DataGrid = mf_Tasks .grdTasks

'-load tasks

LoadTaskGrid

'-Load resource combo

mo_PickList.LoadPickList mf_Tasks.cboResource. PIC_RESOURCE

' -configure task list

ms_Resource = sResource

mf_Tasks.Configure ms_Resource

If sResource «» "" Then   ' -установка источника данных для отображения отдельного задания

ms_TaskFilter = "Assigned =" & Chr$(39) & sResource & Chr$(39)

mo_DataProvider.Filter ms_TaskFi1ter

mo_DataProvider.Sort «Status»

End If

SetReady

End If

With mf_Tasks

WindowState = 0

Show

ZOrder 0

End With

End Sub

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

Как насчет связности и взаимозависимости?

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

Программа управляется объектом clsApplication с глобальной областью действия. Из него создаются и управляются на высоком уровне все остальные объекты. К примеру, в процедуре с понятным именем cLsAppLication.StartApplication создана родительская форма MDI и ряд других вспомогательных объектов. С точки зрения процесса исполнения программы это сугубо положительный момент.

Объявления модулей в 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-операторы. Подобного рода разделение обслуживания сводит взаимозависимость к минимуму и, по моему мнению, существенно облегчает сопровождение и модернизацию электронного администратора.