В режиме «проталкивания» поставщики событий информируют канал событий о том, что событие произошло. Затем канал автоматически распространяет это событие ко всем объектам-клиентам, которые зарегистрировались, выражая свой интерес.
   В режиме «вытягивания» клиенты периодически опрашивают канал событий, который в свою очередь, опрашивает поставщика, предлагающего данные о событии в соответствии с запросом.
   Хотя служба событий CORBA может использоваться для реализации всех событийных моделей, описанных в данном разделе, ее можно рассматривать и в другом качестве. CORBA облегчает связь между объектами, написанными на различных языках программирования и выполняющимися на географически рассредоточенных машинах с различными архитектурами. Находясь на верхнем уровне CORBA, служба событий предоставляет вам способ, отличающийся отсутствием связанности и позволяющий взаимодействовать с приложениями, разбросанными по всему миру и написанными людьми, которых вы никогда не встречали, и пишущими на языках, о которых вы и знать не знаете.
 
   Очевидно, мы не хотим иметь три отдельных копии одних и тех же данных. Поэтому мы создаем модель – сами данные и обычные операции для их обработки. Затем мы можем создать отдельные визуальные представления, которые отображают данные различными способами: в виде электронной таблицы, графика или поля суммы с накоплением. Каждое из этих визуальных представлений может располагать собственными контроллерами. Например, график может располагать неким контроллером, позволяющим приближать и отдалять объекты, осуществлять панорамирование относительно данных. Ни одно из этих средств не оказывает влияния на данные, только на это представление.
   Это и является ключевым принципом, на котором основана парадигма "модель-визуальное представление-контроллер": отделение модели от графического интерфейса, ее представляющего, и средств управления визуальным представлением [35].
   Действуя подобным образом, вы можете извлечь пользу из некоторых интересных возможностей. Вы можете поддерживать множественные визуальные представления для одной и той же модели данных. Вы можете использовать обычные средства просмотра со многими различными моделями данных. Вы даже можете поддерживать множественные контроллеры для обеспечения нетрадиционных механизмов ввода данных.
 
   Подсказка 42: Отделяйте визуальные представления от моделей
 
   Ослабляя связанность между моделью и ее визуальным представлением/контроллером, вы приобретаете большую гибкость практически за бесценок. На самом деле, эта методика является одним из важнейших способов сохранения обратимости (см. "Обратимость").
Java: древовидное визуальное представление
   Хорошим примером принципа "модель-визуальное представление-контроллер" является графический элемент в древовидной схеме Java. Элемент, отображающий дерево, активизируемое щелчком мыши, в действительности представляет собой набор нескольких различных классов, организованных по шаблону "модель-визуальное представление-контроллер".
   Все, что вам нужно сделать для получения полнофункционального элемента дерева, – это обеспечить источник данных, который соответствует интерфейсу TreeModel. Ваша программа становится моделью дерева.
   Визуальное представление создается классами TreeCellRenderer и TreeCellEditor, которые могут быть унаследованы и настроены для обеспечения различных цветов, шрифтов и пиктограмм в графическом элементе. JTree действует в качестве контроллера для элемента дерева и обеспечивает некоторую общую функциональную возможность просмотра.
   Осуществив разделение модели и ее визуального представления, мы серьезно упростили процесс программирования. Уже не нужно беспокоиться об элементе дерева. Вместо этого необходимо предоставить источник данных.
   Предположим, к вам подходит вице-президент фирмы и высказывает пожелание, чтобы вы быстро написали приложение, которое позволяет ему управлять структурной схемой фирмы, содержащейся в унаследованной базе данных на мэйнфрейме. Просто напишите оболочку, которая получает данные с мэйнфрейма, представляет ее в виде TreeModel, и – "Вуаля!" – у вас имеется полнофункциональный элемент дерева.
   Теперь можете капризничать и начать использовать классы средств просмотра; вы можете изменять представление узлов и использовать специальные пиктограммы, шрифты или цвета. Когда вице-президент вернется к вам и скажет, что новые корпоративные стандарты требуют использования для некоторых служащих пиктограммы "Веселый Роджер", то вы можете внести изменения в TreeCellRenderer, не затрагивая другие программы.

Отходя от графических интерфейсов

   Хотя принцип "модель-визуальное представление-контроллер" обычно реализуется в контексте графического интерфейса, на самом деле он является универсальной методикой программирования. Визуальное представление – это некая интерпретация модели (возможно, подмножества), и она не обязана быть графической. Контроллер в большей части является механизмом координации и не должен ассоциироваться с устройством ввода любого типа.
   •  Модель.Абстрактная модель данных, представляющая целевой объект. Модель не располагает непосредственной информацией о любых визуальных представлениях или контроллерах.
   •  Визуальное представление.Способ интерпретации модели. Оно подписывается на изменения в модели и логические события, приходящие от контроллера.
   •  Контроллер.Способ контроля визуального представления и снабжения модели новыми данными. Он осуществляет публикацию событий для модели и визуального представления.
   Рассмотрим пример с текстовым интерфейсом.
   Игра в бейсбол представляет собой уникальное явление. Где еще можно найти такие пустяки, как "самый результативный матч, сыгранный во вторник под дождем при искусственном освещении между командами, названия которых начинаются с гласной буквы"? Предположим, что нам поручили разработать программу для помощи бесстрашным дикторам, которым по должности полагается сообщать счет, статистику и прочие мелочи.
   Ясно, что нам необходима информация о матче, который проходит в настоящее время – играющие команды, условия, игрок, принимающий подачу, счет и т. д. Эти факты образуют наши модели; они будут обновляться по мере поступления новой информации (смена подающего, выбывание игрока, начался дождь…).
   Затем у нас появится ряд объектов – визуальных представлений, которые будут использовать эти модели. Один объект должен наблюдать за набираемыми очками – для обновления текущего счета. Другой объект может получать уведомления о новых игроках, отбивающих мяч, и извлекать краткую справку об их статистических показателях за год. Третий объект может просматривать данные и проверять, не установлен ли мировой рекорд. Можно даже использовать средство просмотра «мелочей», которое несет ответственность за придумывание сверхъестественных и бесполезных фактов, щекочущих нервы зрителей.
 
   Рис. 5.5. Комментирование бейсбольного матча. Средства просмотра являются подписчиками модели.
 
   Но мы не хотим, чтобы несчастный диктор работал со всеми этими окнами непосредственно. Вместо этого мы сделаем так, чтобы каждое из окон генерировало извещения об «интересных» событиях, и обеспечим возможность планирования показа с помощью некоторого высокоуровневого объекта [36].
   Эти объекты (средства просмотра) внезапно стали моделями высокоуровневого объекта, который сам по себе может стать моделью для различных форматирующих средств просмотра. Одно такое средство просмотра могло бы создать сценарий для телесуфлера, с которым работает диктор, второе могло бы генерировать заставки непосредственно на спутниковом канале, а третье могло бы осуществлять обновление web-страниц телевизионной сети или бейсбольной команды (см. рис. 5.5).
   Подобная сеть "модель-средство просмотра" является универсальной (и весьма ценной) методикой проектирования. Каждый канал связи осуществляет отделение исходных данных от событий, их породивших; каждое новое средство просмотра есть некая абстракция. И поскольку отношения представляют собой сеть (а не линейную цепь), то мы обладаем большой гибкостью. Каждая модель может включать в себя много средств просмотра, а одно средство просмотра может работать со многими моделями.
   В усовершенствованных системах, наподобие описанной выше, полезно иметь окна отладки – специализированные окна, которые отображают подробности модели. Дополнение системы средством трассировки отдельных событий также способствует существенной экономии времени.

Все такой же связанный (после стольких лет)

   Несмотря на то, что мы добились уменьшения связанности, прослушивающие процессы и генераторы событий (подписчики и издатели) все равно обладают некоторой информацией друг о друге. Например, в языке Java они обязаны прийти к соглашению об общих определениях интерфейса и вызовах.
   В следующем разделе мы рассмотрим способы дальнейшего уменьшения степени связанности при помощи формы "публикация и подписка", в которой ни один из участников не должен знать друг о друге или обращаться напрямую друг к другу.
Другие разделы, относящиеся к данной теме:
   • Ортогональность
   • Обратимость
   • Несвязанность и закон Деметера
   • Доски объявлений
   • Все эти сочинения
Упражнения
   29. Предположим, что имеется система бронирования авиабилетов, основанная на следующем принципе формирования авиарейса:
   public interface Flight {
   //Return false if flight full.
   public Boolean addPassenger(Passenger p);
   public void addToWaitlJst(Passenger p);
   public int getFlightCapacity();
   public int getNumPassengers();
   }
   Если вы добавляете имя пассажира в лист ожидания авиарейса, то при появлении вакантного места ему будет предложено воспользоваться этим рейсом автоматически.
   Чтобы составить расписание дополнительных рейсов, требуется большая работа с отчетами, заключающаяся в выискивании рейсов, количество мест на которых меньше или равно числу проданных билетов. Это срабатывает, но занимает много времени.
   Нам хотелось бы обладать большей гибкостью при обработке данных о пассажирах в листе ожидания и как-то решить проблемы с этим огромным отчетом – его формирование занимает слишком много времени. Воспользуйтесь идеями, изложенными в данном разделе, чтобы спроектировать этот интерфейс по-новому.

30
Доски объявлений

   На стене написано…

   Обычно вы не связываете понятие изящества с полицейскими детективами. Но рассмотрим пример того, как детективы используют доску объявлений для координации действий и расследования убийства.
   Предположим, что главный инспектор начинает с того, что устанавливает большую доску в комнате для заседаний. На ней он пишет один-единственный вопрос:
   ШАЛТАЙ-БОЛТАЙ (ПОЛ: МУЖСКОЙ, ЧЕЛОВЕК-ЯЙЦО): НЕСЧАСТНЫЙ СЛУЧАЙ ИЛИ УБИЙСТВО?
   Шалтай на самом деле упал, или его толкнули? Каждый детектив может внести свою лепту в раскрытие тайны этого возможного убийства, добавляя факты, показания свидетелей, любые судебные доказательства и т. д. По мере накопления данных детектив может заметить некую связь и также поместить на доску свои наблюдения или гипотезу. Этот процесс продолжается, передается от смены к смене, в нем участвуют различные лица и агенты, пока дело не будет закрыто. Примерный вид доски представлен на рисунке 5.6.
   Некоторые ключевые особенности подхода с применением доски объявлений:
   • Ни один из детективов не обязан знать о существовании какого-либо другого детектива – они лишь смотрят на доску в поисках новой информации и помещают на ней свои находки.
   • Детективы могут пройти подготовку по различным дисциплинам, могут обладать различным уровнем образования и опыта и могут даже не работать на той же территории. Их объединяет желание раскрыть дело и только.
   • Разные детективы могут приходить и уходить в ходе процесса, а также могут работать в различных сменах.
   • На доску можно помещать все, что угодно. Это могут быть изображения, тексты, вещественные доказательства и т. д.
 
   Рис. 5.6. Кто-то обнаружил связь между карточными долгами Шалтая и распечаткой телефонных разговоров. Возможно, ему угрожали по телефону.
 
   Мы работали над несколькими проектами, которые включали в себя сбор распределенных данных или данных о последовательности операций. Каждый проект, решение которого строилось на основе простой модели доски объявлений, давал нам надежную метафору, с которой мы работаем: все вышеперечисленные средства, используемые детективами, также применимы к объектам и программным модулям.
   Доска объявлений позволяет полностью отделять объекты друг от друга, обеспечивая тем самым пространство, на котором потребители и производители информации могут обмениваться данными анонимно и в асинхронном режиме. Как вы могли догадаться, это также позволило уменьшить объем программ, которые нам приходилось писать.

Реализация концепции доски объявлений

   Изначально доски объявлений (на основе компьютеров) разрабатывались в системах искусственного интеллекта для решения крупномасштабных и сложных задач – распознавания речи, принятии решений на основе баз знаний и т. д.
   Современные распределенные системы (подобные доскам объявлений), такие как JavaSpaces и Т Spaces [URL 50, URL 25], основаны на модели пар «ключ-значение», изначально пропагандировавшейся в системе Linda [CG90], где этот принцип был известен под именем "область кортежей".
   При помощи этих систем можно сохранять активные объекты Java (а не только данные) на доске объявлений и извлекать их при частичном соответствии полей (через шаблоны и трафаретные символы) или с использованием подтипов. Предположим, что имеется тип Author, являющийся подтипом Person. Вы можете искать доску объявлений, содержащую объекты Person, используя шаблон Author, в котором параметру lastName присвоено значение «Shakespeare». В результате вы получите автора по имени Bill Shakespeare, а не садовника по имени Fred Shakespeare. Основные операции в системе JavaSpaces:
   Название – Функция
    read  – Осуществляет поиск и извлечение данных из данной области.
    write  – Помещает некий элемент в данную область.
    take  – Подобен read, но также удаляет элемент из данной области.
    notify  – Задает вид уведомления, которое присылается при записи объекта, совпадающего с шаблоном.
   Система Т Spaces поддерживает аналогичный набор операций, но с другими наименованиями и несколько другой семантикой. Обе системы построены подобно базе данных; они обеспечивают элементарные операции и распределенные транзакции, гарантирующие целостность данных.
   Поскольку мы можем хранить объекты, то можно использовать доску объявлений для проектирования алгоритмов, основанных на потоке объектов, а не только на данных. Любой может задать свидетелю вопросы, касающиеся расследования, поместить протокол и переместить свидетеля на другой участок доски, где он отвечал по-другому (если вы дадите и ему прочесть написанное на доске).
   Большим преимуществом систем подобного типа является единственный непротиворечивый интерфейс к "доске объявлений". При построении обычного распределенного приложения вы можете затратить много времени, обрабатывая уникальные вызовы API для каждой распределенной транзакции и интеракции в системе. Проект быстро станет сущим кошмаром, если произойдет комбинаторный взрыв интерфейсов и интеракций.
Как организовать доску объявлений
   Когда детективы ведут расследование крупных дел, то доска объявлений может прийти в беспорядок и найти на ней нужные данные станет сложно. Решение состоит том, чтобы разбить доску на секции и начать каким-то образом упорядочивать данные.
   Различные программные системы осуществляют это разбиение по-разному; одни используют достаточно однородные зоны или группы интересов, тогда как другие используют более иерархичную древовидную структуру.
 
   Стиль программирования под названием "доска объявлений" снимает потребность во многих интерфейсах, позволяя создавать более элегантную и последовательную систему.

Пример приложения

   Предположим, что мы пишем программу для принятия и обработки заявлений на ипотечный кредит или ссуду. Законы, действующие в этой области, отличаются одиозной сложностью, и чиновникам различного уровня всегда есть что сказать по данному поводу. Кредитор обязан убедить заявителя в том, что он должен раскрыть некоторые факты и запросить определенную информацию, но не должен задавать других конкретных вопросов и т. д.
   Помимо отвратительных правовых норм, нам приходится бороться со следующими проблемами.
   • Порядок поступления данных никак не гарантируется. Например, выполнение запросов для проверки кредитоспособности или поиска названия требует существенных временных затрат, тогда как фамилия и адрес могут быть найдены сразу.
   • Сбор данных может осуществляться разными людьми, рассеянными по разным офисам, расположенным в различных часовых поясах.
   • Некоторые данные могут собираться автоматически с помощью других систем. Эти данные могут поступать в асинхронном режиме.
   • И тем не менее, некоторые данные могут находится в зависимости от других данных. Например, вы не сможете начать поиск автомобиля по названию, пока не получите подтверждение права собственности или страховки.
   • Поступление новых данных может вызвать появление новых вопросов и стратегии действий. Предположим, что проверка кредитоспособности заканчивается неубедительным результатом; теперь вам придется заполнить еще пять формуляров и, возможно, сдать анализ крови.
   Вы можете попробовать обрабатывать всевозможные сочетания и обстоятельства, используя систему автоматизации документооборота. Существует большое число подобных систем, но они могут быть сложными и требовать интенсивной работы программистов. При изменении нормативов необходимо менять и документооборот: людям придется изменять процедуры и переписывать встроенную логику.
   Доска объявлений в сочетании с механизмом правил, который включает в себя юридические требования, представляет собой изящное решение имеющих место проблем. Порядок поступления данных является несущественным параметром: регистрация некоего факта активизирует соответствующие правила. Обработка сигналов обратной связи также не представляет труда: результат действия любой совокупности правил может поместить на доску и вызвать активизацию более подходящих в данной ситуации правил.
 
   Подсказка 43: Используйте доски объявлений для координации потоков работ
 
   Можно использовать доску для координации неоднородных фактов и агентов, одновременно сохраняя независимость и даже изоляцию участников друг от друга.
   Вы можете добиться тех же результатов, действуя и более грубыми методами, но в результате получите более хрупкую систему. Когда она сломается, даже "вся королевская конница и вся королевская рать" не смогут заставить работать вашу программу.
Другие разделы, относящиеся к данной теме:
   • Преимущество простого текста
   • Всего лишь визуальное представление
Вопросы для обсуждения
   • Используете ли вы доски объявлений в реальности – памятные записки дома, рядом с холодильником или большие лекционные доски на работе? Что делает их эффективными? Всегда ли формат помещаемых сообщений является последовательным? Имеет ли это значение?
Упражнения
   30. Будет ли уместным использование системы "доска объявлений" для приложений, указанных ниже, или нет? Почему? (Ответ см. в Приложении В.)
   1. Обработка изображений. Несколько параллельных процессов захватывают фрагменты изображения, обрабатывают их и помещают обработанный фрагмент обратно.
   2. Календарное планирование для групп. Есть группа людей, находящихся в разных странах, в различных часовых поясах, говорящих на разных языках и пытающихся спланировать встречу.
   3. Средство мониторинга компьютерной сети. Система осуществляет сбор статистических данных о производительности сети и отчетов о неполадках. Вы хотели бы реализовать несколько программ-агентов, которые могли бы использовать эту информацию для отслеживания неисправностей в системе.

Глава 6
Пока вы пишете программу

   Житейская мудрость гласит, что как только проект переходит в стадию написания текстов программ, работа становится большей частью механической, преобразующей спроектированную конструкцию в набор исполняемых операторов. Мы полагаем, что подобное отношение является единственной и самой серьезной причиной того, что многие программы уродливы, неэффективны, плохо структурированы, сложны в сопровождении и просто ошибочны.
   Написание программ – не механическая процедура. В противном случае CASE-средства, с которыми специалисты связывали свои надежды в начале 80-х годов прошлого века, уже давно заменили бы программистов. Существуют решения, которые необходимо принимать ежеминутно, решения, требующие тщательного обдумывания и оценки, дающие написанной программе право на долгую, праведную и продуктивную жизнь.
   Разработчики, не проявляющие активности при обдумывании своей программы, программируют в расчете на стечение обстоятельств. Программа, может быть, и работает, но этому нет определенного объяснения. В разделе "Программирование в расчете на стечение обстоятельств" мы призываем к большему участию в процессе написания программы.
   Несмотря на то, что большинство составляемых нами программ выполняются быстро, иногда мы разрабатываем алгоритмы, которые способны «посадить» даже Самые быстрые процессоры. В разделе "Скорость алгоритма" обсуждаются методы оценки скорости работы программы и приводятся некоторые подсказки, предупреждающие возникновение потенциальных проблем.
   Прагматики относятся критически ко всем программам, включая собственные. Мы всегда находим резервы улучшения в наших программах и конструкциях. В разделе «Реорганизация» рассматриваются методики, помогающие исправлять существующий текст программы, даже если проект находится в самом разгаре.
   Всякий раз при написании текста программы необходимо помнить следующее: придет время, когда вам нужно будет ее тестировать. Сделайте так, чтобы тестирование не оказалось сложной процедурой, и вероятность того, что программа пройдет тестирование, увеличится. Эту идею мы развиваем в разделе "Программа, которую легко тестировать".
   И наконец, в разделе "Злые волшебники" говорится о том, что необходимо быть осторожным с инструментальными средствами, генерирующими миллионы строк от вашего имени, если вы не понимаете сути работы этих средств.
   Многие из нас в значительной степени управляют автомобилем "на автопилоте" – мы не даем явных указаний ноге, чтобы она нажала на педаль, или руке, чтобы она повернула руль, а мысленно говорим себе: "снизить скорость и повернуть направо". Но дисциплинированные водители постоянно контролируют ситуацию, отыскивают потенциальные проблемы и оказываются в нужном положении, если происходит непредвиденное. Это применимо и к написанию программ – возможно, об этом говорилось уже много раз, но хладнокровие всегда позволит вам предотвратить катастрофу.

31
Программирование в расчете на стечение обстоятельств

   Случалось ли вам когда-нибудь смотреть старые черно-белые фильмы о войне? Усталый солдат осторожно выбирается из зарослей кустарника. Впереди него свободное пространство, и солдат задается вопросом: есть ли впереди мины или можно безбоязненно идти дальше? Ничто не говорит о том, что впереди минное поле, – нет ни знаков, ни колючей проволоки, ни воронок. Солдат пробует штыком грунт впереди себя и вздрагивает в ожидании взрыва. Но ничего не происходит. Какое-то время он продолжает осторожно продвигаться но полю, прощупывая грунт. В конце концов, убедившись, что проход безопасен, он распрямляется и начинает гордо маршировать вперед… навстречу смерти.
   Первые поиски мин, проведенные солдатом, были безрезультатны, но ему просто повезло. Он пришел к ложному заключению, которое закончилось катастрофой.
   Программисты также работают на заминированной территории. Существуют сотни ловушек, подстерегающих нас ежедневно. Помня об истории с солдатом из фильма, нам стоит опасаться ложных заключений. Необходимо избегать программирования в расчете на стечение обстоятельств, полагаясь на удачу и случайные успехи, и сделать выбор в пользу преднамеренного программирования.

Как программировать в расчете на стечение обстоятельств

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