Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Лучшие статьи журнала «Компьютеры+Программы»


Информационный Канал Subscribe.Ru

Здравствуйте, уважаемые читатели!

В этом выпуске рассылки публикуется статья, занявшая по результатам голосования второе место.


Павел Цытович,
pavel@comp.susu.ac.ru

Структурные модели программных систем

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

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

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

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

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

Классическая модель

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

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

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

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

Примером программного продукта, в котором реализована классическая структурная модель, является любая утилита командной строки, такая как regsrvr32.exe (регистрация COM-серверов) или sn.exe (генерация «сильного имени») в .NET Framework. Однако наиболее ярко классическая модель проявляется в CGI-сценариях, создаваемых на языках Perl, PHP и т.п. Один такой сценарий, в основу которого положены объектно-ориентированные возможности языка PHP, реализует «движок» сайта (см. напр., http://www.comp.chelcom.ru/~pavel). «Движок» состоит из трех блоков, которые анализируют параметры запроса, обрабатывают запрос в объекте подкласса, «родителем» которого является класс Command, и формируют выходной документ средствами XML и XSLT. Для иллюстрации данной структурной модели рассмотрим некоторые фрагменты этого движка.

Итак, программа анализирует запрос, после чего создает объект соответствующего класса — по сути, блок обработки:
if (ereg ('Command=('.$AvailCommand.')',$REQUEST_URI,$Rez))
$Cmd = new $Rez [1]($User,$db);
//создать объект-обработчик команды

Затем управление передается одному из методов объекта $Rez:
$Cmd->HandleRequest ($ContentObject);

Здесь ContentObject — объект, в котором формируется XML-текст с последующим преобразованием в HTML. В методе HandleRequest() команда обрабатывается определенным образом, после чего вызывается шаблон контента с подстановкой в него параметров:
function HandleRequest (&$ContentObject)
{
$this->db->Prepare (»SELECT * FROM ROOM WHERE IDROOM=».
$this->CurrentUser->CurrentRoom);
//формируем SQL-запрос
$this->db->Open ();
//выполняем его
//получаем запись из таблицы
$room = $this->db->GetAndMoveNext () or die (»нет требуемой комнаты»);
$param = array ();
$ContentObject->GetTemplate ($room->XMLNAME);
//устанавливаем шаблоны
$ContentObject->GetXSLT ($room->XSLTNAME);
//считываем XSLT-шиблон
$param [»@RoomName»] = $room->ROOMNAME;
$ContentObject->SetXMLParam ($param);
//применяем параметры
return true;
}

На последнем шаге XML-документ преобразуется в HTML и выводится в поток (здесь param — набор дополнительных параметров, передаваемых в XSLT):
echo $ContentObject->BuildHtml ($Param); //вывести документ

Событийно-ориентированная модель

Событийно-ориентированные программные системы получили широкое распространение в системах c графическим пользовательским интерфейсом. В настоящее время такие модели являются негласным стандартом архитектуры программных систем.

В событийно-ориентированных системах каждый элемент интерфейса рассматривается как независимый объект, способный информировать программу об изменении своего состояния при помощи события. Однако область применения событий не ограничивается интерфейсом пользователя. Ведь под событием можно понимать и то, что относится к предметной области программы. Поэтому прежде, чем идти дальше, дадим определение события:

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

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

Назначение интерфейса пользователя — преобразовывать действия пользователя в события программной системы. Перечень таких событий составляется на этапе проектирования программной системы. Часто используется стандартный перечень событий, определяемый интерфейсом пользователя.

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

Это правило наглядно демонстрируется следующим примером. В программе, реализующей текстовый редактор, есть два события: «открытие файла» и «сохранение файла». Принцип независимости блоков требует, чтобы блок реакции на событие «сохранение файла» не проверял, был ли ранее открыт сохраняемый файл. Обеспечение такой независимости возлагается на третью часть программной системы.

Диспетчер событий обеспечивает передачу управления блоку реакции на события при наступлении события. Кроме того, диспетчер событий имеет «полномочия» не реагировать на некоторое событие в определенных условиях. Таким образом, диспетчер событий играет ключевую роль в событийно-ориентированной программной системе. Именно он, а не блок реакции на события, отвечает за корректное поведение программы.

Событийно-ориентированные приложения рекомендуется создавать в следующей последовательности:

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

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

Открытая программная система

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

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

Открытая программная система состоит из следующих частей:

  • интерфейс пользователя;
  • блок обработки данных;
  • средства конфигурирования.

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

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

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

  • программированные управляющие алгоритмы;
  • взаимозаменяемые модули;
  • интерфейс программирования.

Программированные управляющие алгоритмы

Программная система, основанная на программированных управляющих алгоритмах, предоставляет пользователю средства программирования высокого уровня. Используя эти средства, пользователь программирует управляющий алгоритм на некотором языке программирования, ориентированном на предметную область программной системы.

Основу такой программной системы составляет так называемая виртуальная машина. Под виртуальной машиной понимается некий абстрактный компьютер, на котором выполняются программы, не ориентированные на какую-либо аппаратную платформу. Виртуальная машина преобразует команды абстрактного процессора в конкретную последовательность действий — непосредственно интерпретирует программы на языке высокого уровня либо использует образ программы, получаемый в результате предварительной трансляции.

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

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

Взаимозаменяемые модули

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

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

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

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

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

Интерфейс программирования

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

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

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

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

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

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

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

В ходе эксплуатации ранних версий проекта стало ясно, что алгоритм тестирования должен меняться в зависимости от группы студентов, требований преподавателей и т.п. Существовавшие на тот момент тестирующие системы не удовлетворяли этому требованию. Поэтому в основу «Teach Wizard» была заложена технология открытой программной системы на основе интерфейса программирования.

Для этого был разработан набор сервисов, объединенных под маркой «Teach Wizard API». Эти сервисы представляют собой функции языка С++. В качестве примера приведу некоторые из них:
BOOL GetQuestionFromList (int Num,QUESTIONINFO *qInfo);
//дать заголовок вопроса из списка
//возвращаемое значение = FALSE вопроса с таким номером нет
void DeleteQuestionFromList (int Num);
//удалить вопрос из списка
//функция не будет работать после начала тестирования (только для SortQuestion)
BOOL ExchangeQuestionFromList (int Num1,int Num2);
//поменять вопросы местами в списке
//функция не будет работать после начала тестирования (только для SortQuestion)
void ForceNextQuestion ();
//перейти принудительно к следующему вопросу
void ForceEndTest ();
//принудительно завершить тест
void RunTimer (int timervalue);
//запустить таймер
void StopTimer ();
//остановить таймер

Эти сервисы ядра программной системы вызываются внешним модулем при выполнении управляющего алгоритма. С другой стороны, для того чтобы та или иная часть управляющего алгоритма начала выполняться, каждый внешний модуль реализует ряд сервисов, которые вызываются ядром. Вот некоторые из них:
BOOL QueryQuestion (QUESTIONINFO* qInfo);
//показывать ли данный вопрос в тесте
int QueryBall ();
//вызывается, когда необходимо посчитать итоговый балл
BOOL GetDiagramData (int* value,int* color);
//вызывается, когда нужно
//получить вид диаграммы в зависимости от теста
//FALSE — последняя диаграмма
int GetNextQuestion (int CurrentQuestion,BOOL* Last);
//вызывается когда
//требуется перейти к следующему вопросу
void OptionDialog ();
//вызывается, когда нужно отобразить диалог настройки опций теста

Таким образом, интерфейс программирования позволил реализовать программную систему, которая может изменяться в зависимости от потребностей пользователя.

Смешанная модель

В крупных программных системах часто применяется смешанная модель, основанная на событийно-ориентированном подходе. Разные блоки такой программной системы могут использовать все рассмотренные выше технологии.

Примером программной системы, построенной на базе смешанной модели, является программная система «Microsoft Word». Поскольку этот текстовый процессор является Windows-приложением, в его основу положена событийно-ориентированная модель. Поддержка словарей и тезаурусов организована на основе технологии взаимозаменяемых модулей: каждый внешний модуль реализует поддержку конкретного языка. Расширение функциональных возможностей программы в виде подсистемы макросов на языке высокого уровня Visual Basic for Application организовано на основе технологии «программированных управляющих алгоритмов».

Заключение

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

Павел Цытович,
доцент кафедры ЭВМ,
Южно-Уральский государственный университет

pavel@comp.susu.ac.ru


Задать вопрос
Прислать свою статью для публикации в журнале
Просто поговорить

До следующего выпуска!
Елена Полонская, редактор "К+П"
www.comizdat.com

Перепечатка материалов этой рассылки разрешается только по согласованию с редакцией журнала "Компьютеры+Программы"



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное