Планирование расписания поездов
Мы уже говорили, что концепция плана движения поезда является центральной для функционирования системы управления движением. Каждый поезд имеет один активный план, а каждый план предназначен только одному поезду. Он может содержать много различных приказов и точек на пути.
Наш первый шаг состоит в точном определении того, из каких частей состоит план поезда. Для этого мы должны перечислить всех потенциальных клиентов плана и выявить способ его использования каждым из них. Например, некоторым клиентам может быть разрешено составлять планы, другим - корректировать планы, а остальные смогут только читать планы. В этом смысле план выступает как хранилище информации, связанной с маршрутом одного отдельного поезда и действиями во время движения. Примером таких действий может быть отцепление или подцепление вагонов.
На рис. 12-6 приведены стратегические проектные решения, касающиеся структуры класса TrainPlan. Как и в главе 10, мы используем диаграмму классов, чтобы показать части, из которых состоит план движения поезда (подобно тому, как это делается на традиционных диаграммах 'сущность-связь'). Мы видим, что каждый план содержит одну бригаду, но может включать в себя много приказов и действий. Мы ожидаем, что эти действия будут упорядочены во времени и что с каждым действием связана такая информация, как время, местоположение, скорость, ответственное лицо, приказы. Например, план может содержать следующие действия:
Время Положение Скорость Ответственное лицо Приказ
0800 Pueblo Как указано Начальник депо Покинуть депо
1100 Colorado Springs 40 миль/ч Отцепить 30 вагонов
1300 Denver 40 миль/ч Отцепить 20 вагонов
1600 Pueblo Как указано Вернуться в депо
Из рис. 12-6 видно, что класс TrainPlan имеет один статический объект типа UniqueId, так называемое магическое число, однозначно идентифицирующее каждый экземпляр класса TrainPlan.
Как это делалось для класса Message и его подклассов, можно в первую очередь спроектировать наиболее важные элементы плана движения поезда; детали будут проясняться по мере того, как мы будем использовать план для разных клиентов.
Одновременное наличие огромного числа активных и неактивных планов поездов возвращает нас к проблеме базы данных, о которой мы уже говорили. Диаграмма классов на рис. 12-6 может служить наброском логической схемы этой базы данных. При этом возникает следующий вопрос: где хранится план поезда?
В совершенном мире, где нет помех или задержек при передаче и где неограниченны ресурсы компьютеров, лучше всего было бы разместить все планы движения поездов в единой центральной базе данных. Такой подход обеспечивает существование единственного экземпляра каждого плана. Однако реальные условия делают это решение неэффективным: неизбежны задержки при передаче, производительность процессоров ограничена. Таким образом, скорость доступа к плану, который расположен в диспетчерском центре, с поезда, не будет отвечать требованиям реального времени. Однако, с помощью программного обеспечения можно создать иллюзию централизованной базы данных. Наше решение заключается в том, что планы поездов будут располагаться на компьютерах диспетчерского центра, а копии этих планов будут по мере необходимости распределяться по узлам сети. Для обеспечения эффективности компьютер каждого поезда может хранить копию своего плана. Таким образом, бортовое программное обеспечение может получить нужные сведения с пренебрежимо малой задержкой. Если план изменяется в результате действий диспетчера или (что менее вероятно) по решению машиниста, наше программное обеспечение должно гарантировать, что все копии этого плана обновятся, причем за разумное время.
На рис. 12-7 показано, как происходит передача и обновление копий плана. Первичная копия плана движения находится в централизованной базе данных в диспетчерском центре и может быть разослана по любому числу узлов сети. Когда какой-либо клиент (используя операцию get с уникальным UniqueId в качестве аргумента) запрашивает план, первичная версия копируется и посылается клиенту. В базе данных регистрируется местоположение копии, а сама копия плана сохраняет связь с базой данных. Теперь предположим, что в результате действий машиниста появилась необходимость изменить план движения поезда. Сначала изменяется копия плана, находящаяся на поезде. Затем сообщение об изменениях посылается в централизованную базу данных на диспетчерский центр. После того, как план изменился в базе данных, сообщения об изменениях рассылаются всем остальным клиентам, которые имеют у себя копии данного плана.
Этот механизм правильно работает и в том случае, когда изменения в план движения вносит диспетчер; при этом сначала изменяется копия плана в базе данных, а затем сообщения об изменениях рассылаются но сети остальным клиентам. Как в обоих случаях осуществляется передача изменении? Для этого мы используем механизм передачи сообщений, разработанный нами ранее. Заметим, что в результате проектирования мы добавили новое сообщение: изменение плана движения поезда. Таким образом, механизм передачи планов движения базируется на уже существующем низкоуровневом механизме передачи сообщений.
Использование готовой коммерческой СУБД на диспетчерских компьютерах позволит обеспечить резервирование данных, восстановление, ведение контрольного журнала и секретность информации.
Отображение информации
Использование готовых технологических решений для базы данных позволяет нам сосредоточиться на специфике задачи. Такого же результата можно добиться и в механизмах отображения информации, если использовать стандартные графические средства, например, Microsoft Windows или Х Windows. Использование готовых графических программных средств поднимает уровень абстракции нашей системы настолько, что разработчикам не надо беспокоиться об отображении информации на уровне пикселей. Кроме того, очень важно инкапсулировать проектные решения о графическом представлении различных объектов.
Рассмотрим, например, отображение информации о профиле и качестве участков пути. Требуется, чтобы изображение появлялось в двух местах: в диспетчерском центре и на поезде (где отображается путь только впереди поезда). Предполагая, что мы имеем некоторый класс, экземпляры которого представляют участки пути, можно рассмотреть два подхода к визуализации этого объекта. В соответствии с первым подходом, создается специальный объект, управляющий отображением, который преобразует состояние объекта в визуальную форму. Согласно второму подходу мы отказываемся от специального внешнего объекта и в каждый наш объект включаем информацию о том, как его отображать. Мы считаем, что второй подход предпочтительней, так как он проще и лучше отражает сущность объектной модели.
Однако, этот подход не лишен недостатков. Мы, вероятно, получим множество разновидностей отображаемых объектов, каждый из которых создан разными группами разработчиков. Если реализовывать каждый отображаемый объект отдельно, то возникают избыточный код. несогласованность стиля и вообще большая путаница. Правильнее проанализировать все разновидности отображаемых объектов, определить, какие у них общие элементы и создать набор промежуточных классов, который обеспечит отображение этих общих элементов. В свою очередь, промежуточные классы могут быть построены на основе коммерческих низкоуровневых графических пакетов.
На рис. 12-8 показано проектное решение о реализации всех отображаемых объектов с помощью общих утилит класса. Эти утилиты построены на основе низкоуровневого интерфейса Windows, который скрыт от всех высокоуровневых классов. На самом деле, процедуры Windows API трудно воплотить в одном классе или утилите. Наша диаграмма немного упрощена; вероятно, реализация потребует услуг нескольких классов