» Главная
eXcode.ru » Статьи » Другие » Основы объектно-ориентированного проектирования
» Новости
» Опросы
» Файлы
» Журнал



Пользователей: 0
Гостей: 8





ОО-метод для графических интерактивных приложений




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

Фольклор Unix′а. (Вместо "Знаменитый Конструктор" использовалось настоящее имя одного из главных создателей ОС Unix.)

Необходимые средства

Какие средства нужны для создания полезных и приятных интерактивных приложений?

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

Для устранения непонимания начнем с терминологии. Слово "пользователь" (одно из самых оскорбительных для компьютерщиков) здесь может ввести в заблуждение. Некоторые люди, называемые разработчиками приложений, создают интерактивные приложения, используемые другими людьми, называемыми конечными пользователями. Разработчики приложений, в свою очередь, рассчитывают на графические средства, созданные третьей группой - разработчиками инструментальных средств. Существование этих трех категорий объясняет, почему слово "пользователь" без дальнейшего уточнения неоднозначно: конечные пользователи являются пользователями разработчиков приложений, но сами разработчики приложений являются пользователями разработчиков инструментальных средств.

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

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

Графические системы, оконные системы, инструментальные средства

Многие вычислительные платформы предлагают средства для построения графических интерактивных приложений. Для реализации графики имеются соответствующие библиотеки такие, как GKS и PHIGS. Что касается интерфейса пользователя, то базовые оконные системы (такие, как Windows API, Xlib API под Unix′ом и Presentation Manager API под OS/2) имеют чересчур низкий уровень, чтобы ими было удобно пользоваться разработчикам приложений, но они дополняются "инструментариями", например, основанными на протоколе интерфейса пользователя Motif.

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

  • Их трудно использовать. Чтобы освоить инструментальные средства, основанные на протоколе Motif, разработчики должны изучить многотомную документацию, описывающую сотни встроенных функций на Си и структур, носящих такие внушающие благоговейный ужас имена как XmPushButtonCallbackStruct , где в Button буква B большая, а в back - b малая. К трудностям и небезопасности C добавляется сложность инструментария. Использование базового интерфейса программирования приложений API в Windows также утомительно.
  • Хотя предлагаемый инструментарий включает объекты пользовательского интерфейса - кнопки, меню и т. п., - у некоторых из них хромает графика (геометрические фигуры и их преобразования). Для добавления в интерфейс настоящей графики требуются значительные усилия.
  • Различные инструментальные средства несовместимы друг с другом. Графика Motif, Windows и Presentation Manager, основанная на похожих понятиях, имеет множество различий. Некоторые из них существенны. Так, в Windows и PM создаваемый объект интерфейса сразу же выводится на экран, а в Motif сначала строится соответствующая структура, а затем вызов операции "реализовать" ее показывает. Некоторые различия связаны с разными соглашениями (координаты экрана откладываются от верхнего левого угла в PM и от нижнего левого угла у других). Многие соглашения об интерфейсах пользователя также различны. Большинство этих различий доставляет неприятности конечным пользователям, желающим иметь нечто работающее и "приятно выглядящее" и которым неважно, какие углы у окна - острые или слегка закругленные. Эти различия еще больше неприятны разработчикам, которые должны выбирать между потерей части их потенциального рынка и тратой драгоценного времени на усилия по переносу.

Библиотека и конструктор приложений

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

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

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

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

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

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

Применение ОО-подхода

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

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

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

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

Переносимость и адаптация к платформе

Некоторые разработчики приложений предпочитают переносимые библиотеки, позволяющие написать один исходный текст системы. Для переноса системы на другую платформу достаточно ее перекомпилировать, не внося никаких изменений. Другие хотели бы обратного: получить полный доступ ко всем специфическим элементам управления и прочим "штучкам" конкретной платформы, например, Microsoft Windows, но в удобном виде (а не на низком уровне стандартных библиотек). Третьи хотели бы понемногу и того и другого: переносимости по умолчанию и возможности, если потребуется, стать "родным" для данной платформы.

При аккуратном проектировании, основанном на двухуровневой структуре, можно попытаться удовлетворить все три группы:

Архитектура графической библиотеки
Рис. 14.1. Архитектура графической библиотеки

Для конкретизации на рисунке приведены имена соответствующих компонентов из окружения ISE, но идея применима к любой графической библиотеке. На верхнем уровне (Vision) находится переносимая графическая библиотека, а на нижнем уровне - специализированные библиотеки, такие как WEL для Windows, каждая из них приспособлена к "своей" платформе.

WEL и другие библиотеки нижнего уровня можно использовать непосредственно, но они также служат как зависящие от платформы компоненты верхнего уровня: механизмы Vision реализованы посредством WEL для Windows, посредством MEL для Motif и т. д. У такого подхода несколько преимуществ. Разработчикам приложений он дает надежду на совместимость понятий и методов. Разработчиков инструментальных средств он избавляет от ненужного дублирования и облегчает реализацию высокого уровня, базирующуюся не на прямом всегда опасном интерфейсе с C, а на ОО-библиотеках, снабженных утверждениями и наследованием, таких как WEL. Связь между этими двумя уровнями основана на описателях (см. лекцию 6).

У разработчиков приложений имеется выбор:

  • Для обеспечения переносимости следует использовать верхний уровень. Он также представляет интерес для разработчиков, которые, даже работая для одной платформы, хотят выиграть от более высокой степени абстракций, предоставляемых такими библиотеками высокого уровня, как Vision.
  • Для получения прямого доступа ко всем специфическим механизмам некоторой платформы (например, многочисленным элементам управления, предоставляемым Windows NT), следует перейти на соответствующую библиотеку нижнего уровня.

Рассмотрим один тонкий вопрос. Как много специфических для данной платформы возможностей допустимо потерять при использовании переносимой библиотеки? Корректный ответ на него является результатом компромисса. Некоторые из первых переносимых библиотек использовали подход пересечения ("наименьшего общего знаменателя"), ограничивающий предлагаемые возможности теми, которые предоставляются всеми поддерживаемыми платформами. Как правило, этого недостаточно. Авторы библиотек могли использовать и противоположный подход - объединения: предоставить каждый из механизмов каждой из поддерживаемых платформ, используя точные алгоритмы для моделирования механизмов, первоначально отсутствующих на той или иной платформе. Такая политика приведет к огромной и избыточной библиотеке. Правильный ответ находится где-то посередине: для каждого механизма, присутствующего не на всех платформах, авторы библиотеки должны отдельно решать, достаточно ли он важен для того, чтобы промоделировать его на всех платформах. Результатом должна явиться согласованная библиотека, достаточно простая, чтобы использоваться без знаний особенностей отдельных платформ, и достаточно мощная для создания впечатляющих графических приложений.

Для разработчиков приложений еще одним критерием в выборе между двумя уровнями служит эффективность. Если основной причиной выбора верхнего уровня служит абстрактность, а не переносимость, то можете быть уверены - включение дополнительных классов приведет к потерям в памяти. Для правильно спроектированных библиотек потерями времени можно обычно пренебречь. Поэтому эффективность по памяти определяет, нужно ли это делать. Ясно, что библиотека для одной платформы (например, WEL) будет более компактной.

Наконец, заметим, что оба решения не являются полностью взаимоисключающими. Можно сделать основную часть работы на верхнем уровне, а затем добавить "бантики" для пользователей, работающих с библиотекой для самой продаваемой платформы. Конечно, это следует делать аккуратно, беззаботное смешение переносимых и непереносимых элементов быстро ликвидирует любую ожидаемую выгоду от переносимой разработки. Один элегантный образец проекта (используемый ISE в некоторых своих библиотеках) основан на попытке присваивания (см. лекцию 16 курса "Основы объектно-ориентированного программирования"). Его идея в следующем. Рассмотрим некоторый графический объект, известный через сущность m, тип которой определен на верхнем уровне, например, MENU. Всякий актуальный объект, к которому она будет присоединяться во время исполнения, будет, конечно, специфическим для платформы, т. е. будет экземпляром некоторого класса нижнего уровня, скажем, WEL_MENU. Для применения специфических для платформы компонентов требуется некоторая сущность этого типа, скажем wm. Далее можно воспользоваться следующей схемой:

wm ?= m
if wm = Void then
... Мы не под Windows! Ничего не делать или заниматься другими делами...
else
... Здесь можно применить к wm любой специфический для Windows компонент WEL_MENU ...
end

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

Графические абстракции

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

Фигуры (изображения)

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

Прекрасную модель представляют географические карты. Карта (страны, области, города) дает визуальное представление некоторой реальности. Проектирование карты использует несколько уровней абстракции:

  • Мы должны видеть реальность, стоящую за моделью (в почти абстрактном виде), как множество геометрических форм или фигур. На карте эти фигуры представляют реки, дороги, города и другие географические объекты.
  • Карта описывает некоторое множество фигур, называемое миром.
  • Карта показывает только часть мира - одну или более областей, называемых окнами. Окна имеют прямоугольную форму. Например, у карты может быть одно главное окно, посвященное стране, и вспомогательные окна, посвященные большим городам или удаленным частям (например, Корсике на картах Франции или Гавайям на картах США).
  • Физически карта появляется на физическом носителе изображения, устройстве. Этим устройством обычно является лист бумаги, но им может быть и экран компьютера. Различные части устройства будут предназначены для разных окон.

Графические абстракции
Рис. 14.2. Графические абстракции

Четыре базовых понятия - WORLD, FIGURE, WINDOW, DEVICE - легко переносятся на общие графические приложения, в которых мир может содержать произвольные фигуры, представляющие интерес для некоторого компьютерного приложения, а не только представления географических объектов. Прямоугольные области мира (окна) будут изображаться на прямоугольных областях устройства (экрана компьютера).

На рис. 14.2 показаны три плоскости: мир (вверху), окно (посредине) и устройство (внизу). Понятие окна играет центральную роль, поскольку каждое окно связано как с некоторой областью мира, так и с некоторой областью устройства. С окнами также связано единственное существенное расширение базовых понятий - поддержка иерархически вложенных окон. У наших окон могут быть подокна (без всяких ограничений на уровень вложенности). (На рисунке вложенных окон нет.)

Координаты

Нам нужны две системы координат: координаты устройства и мировые координаты. Координаты устройства задают положения элементов, изображаемых на этом устройстве. На экранах компьютеров они часто измеряются в пикселах; пиксел (элемент изображения) - это размер маленькой точки, обычно самого малого из изображаемых элементов.

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

Так как окно отражает часть мира, то у него есть некоторое местоположение (определяемое мировыми координатами x и y его верхнего левого угла) и некоторые размеры (длина по горизонтали и вертикали соответствующей части мира). Местоположение и размеры выражаются в единицах мировых координат.

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

Операции над окнами

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

Таблица 14.1. Установка позиций окна
Установка абсолютного положенияСдвиг относительно текущей позиции
Положение в миреgopan
Положение на устройстве

place_proportional

place_pixel

move_proportional

move_pixel

Процедуры _proportional интерпретируют значения своих аргументов как отношение высоты и ширины окна родителя, а аргументами остальных процедур являются абсолютные значения (в мировых координатах для go и pan, и в координатах устройства для процедур _pixel). Имеются аналогичные процедуры и для задания размеров окна.

Графические классы и операции

Все классы, представляющие фигуры, являются наследниками отложенного класса FIGURE, среди стандартных компонентов которого имеются display (показать), hide (скрыть), translate (сдвинуть), rotate (повернуть), scale (масштабировать).

Безусловно, множество фигур должно быть расширяемым, позволяя разработчикам приложений (и, опосредованно, конечным пользователям графических средств) определять их новые типы. Мы уже видели, как это можно сделать: предоставить класс COMPOSITE_FIGURE, построенный с помощью множественного наследования из класса FIGURE и такого типа контейнера, как LIST [FIGURE].

Механизмы взаимодействия

Обратим теперь внимание на то, как наши приложения будут взаимодействовать с пользователями.

События

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

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

... Выполняет некоторые вычисления ...
print ("Введите, пожалуйста, значение параметра xxx.")
read_input
xxx := value_read
... Продолжает вычисление до тех пор, пока снова не потребуется получить 
некоторое значение от пользователя ...

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

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

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

Кроме того, должна быть возможность определять в программах собственные события, сообщения о появлении которых компоненты ПО могут посылать в явном виде с помощью процедуры вида raise(e).

Контексты и объекты интерфейса пользователя

Инструментальные средства GUI предлагают множество готовых "Объектов интерфейса пользователя": окна, меню, кнопки, панели. Вот пример кнопки OK.

Кнопка ОК
Рис. 14.3. Кнопка ОК

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

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

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

Наиболее общие контексты связаны с объектами интерфейса пользователя. Показанная выше кнопка задает логическое условие-контекст "курсор мыши на кнопке (внутри)?" Контексты такого рода будут записываться в виде IN (uio), где uio - это объект интерфейса пользователя.

Для каждого контекста c его отрицание not c также является контекстом; not IN (uio) называется также OUT (uio). Контекст ANYWHERE всегда истинен, а его отрицание NOWHERE всегда ложно.

У нашего конструктора приложений будет каталог контекстов, в который будут входить ANYWHERE и контексты вида IN(uio) для всех объектов интерфейса пользователя uio. Кроме того, хочется предоставить разработчикам приложений возможность определять собственные контексты, для этой цели конструктор приложений предоставит специальный редактор. Среди прочего, этот редактор позволит получать контекст not c по любому c (в частности, и по c из каталога).

Обработка событий

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

Команды

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

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

К обсужденным выше компонентам добавим еще атрибут exit_label, объясняемый ниже.

Базисная схема

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

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

Состояния

Более полная схема включает дополнительный уровень абстракции, дающий модель Контекст-Событие-Команда-Состояние (Context-Event-Command-State) интерактивных графических приложений.

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

Команда выхода
Рис. 14.4. Команда выхода

В этом состоянии приложение распознает различные события в различных контекстах; например, можно щелкнуть по фигуре, чтобы ее передвинуть, или запросить команду сохранения Save, щелкнув кнопку OK. В этом последнем случае появляется новая панель:

Подтверждение команды
Рис. 14.5. Подтверждение команды

На этой стадии будут допустимы только две комбинации контекст-событие: щелчок кнопки OK или щелчок кнопки Cancel на новой панели. Приложение сделает остальную часть изображения "серой", напомнив тем самым, что все, кроме этих двух кнопок, временно не активно. Сессия перешла в новое состояние. Понятие состояния, также иногда называемого режимом, знакомо по дискуссиям об интерактивных системах, но редко определялось точно. Теперь у нас есть предпосылки для формального определения: состояние характеризуется множеством допустимых в нем комбинаций контекстов и событий и множеством команд; для каждой допустимой комбинации контекст-событие состояние задает связанную с ней команду. Ниже это будет переформулировано в виде математического определения.

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

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

  • В основном состоянии (которое является также начальным для конечного пользователя, вызывающего редактор на новом файле) нажатие на клавишу с буквой будет в большинстве случаев приводить к выполнению команды, связанной с этой буквой. Например, нажатие на x удаляет символ в позиции курсора, если таковой символ имеется, двоеточие переводит в командное состояние, нажатие на i переводит в состояние вставки, а нажатие R переводит в состояние замены. Некоторые символы не определяют события, например, нажатие z не имеет эффекта (если с ним не связан какой-либо макрос).
  • В командном состоянии единственное, что допустимо, - это ввод команд в окне Vi, таких как "save" или "restart".
  • В состоянии вставки в качестве событий допустимы нажатия клавиш с печатаемыми символами, при этом соответствующий символ вставляется в текст, вызывая сдвиг имеющегося текста вправо. Клавиша ESCAPE возвращает сессию в основное состояние.
  • Состояние замены является вариантом состояния вставки, в котором печатаемые символы заменяют существующие, а не сдвигают их.

Частичная диаграмма состояний для Vi
Рис. 14.6. Частичная диаграмма состояний для Vi

Литература по интерфейсам пользователей настроена критически к состояниям, потому что они могут вводить пользователей в заблуждение. В одной старой статье о пользовательском интерфейсе языка Smalltalk [Goldberg 1981] имеется фотография автора в футболке с надписью "Долой режимы!"( "Don′t mode me in!"). Действительно, общий принцип разработки хорошего интерфейса пользователя состоит в том, чтобы обеспечить конечным пользователям на каждом этапе сессии возможность выполнять все имеющиеся в их распоряжении команды (вместо того, чтобы заставлять их изменять состояние для выполнения некоторых важных команд).

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

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

Поэтому наш конструктор приложений предоставит разработчикам в явном виде абстракцию STATE (СОСТОЯНИЕ); что касается других абстракций, то в нем будет каталог состояний, содержащий состояния, полезные для общего использования, и редактор состояний, позволяющий разработчикам определять новые состояния, часто получаемые с помощью модификации состояний, извлеченных из каталога.

Приложения

Последней из главных абстракций данных является понятие приложения.

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

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

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

Контекст-Событие-Команда-Состояние: резюме

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

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

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

Некоторые из неформально представленных в этой лекции понятий, в частности понятие состояния, имеют элегантное математическое описание, основанное на понятии конечной функции и математическом преобразовании, известном как карринг (currying).

Поскольку эти результаты не используются в остальной части книги и представляют интерес в основном для читателей, которым нравится исследовать математические модели понятий, связанных с ПО, то соответствующие разделы вынесены на компакт-диск, сопровождающий эту книгу, в виде отдельной главы, названной "Математические основы"1), взятой из [M 1995e].

Библиографические замечания

Идеи конструктора приложений, кратко описанного в этой лекции, взяты в значительной мере из конструктора приложений Build фирмы ISE, детально описанного в [M 1995e], где также приведено подробное описание лежащей в его основе математической модели.

1) Эта дополнительная глава переведена на русский язык, но, следуя автору, помещена на CD. Здесь же отмечу, что под каррингом понимается понижение на единицу размерности функции. Поскольку чудес не бывает, то естественно на единицу возрастает размерность результата - если ранее он был числом, то после карринга он становится функцией, возвращающей число. Объектный подход весь основан на карринге. Вызов x.f(a) объектом x метода f(a) можно рассматривать как применение карринга к некоторой исходной функции от двух аргументов F(x,a), так что f(a) = curry(F(x,a)). - Прим. ред.
К началу статьи





Добавил: MadvEXДата публикации: 2006-02-28 01:39:56
Рейтинг статьи:3.00 [Голосов 6]Кол-во просмотров: 6891

Комментарии читателей

Всего комментариев: 0
Ваше имя: *
Текст записи: *
Имя:

Пароль:



Регистрация

Как вы относитесь к рекламе на сайтах.
Отрицательно, терпеть ее не могу!
46% (95)
С пониманием
25% (51)
Пусть будет, если только по делу
15% (32)
Она мне безразлична!
11% (23)
Я ее обожаю!
3% (6)

Проголосовало: 208
Фидошник едет в тpоллейбyсе и оpет:
- Сакс, сакс!!!!
Бабyлька pядом говоpит емy:
- Hy что все сакс, да сакс... Ты еще какие-нибyдь слова знаешь?
- Да, Windows...
- А что это?
- САКС!!!!!
Рейтинг: 1/10 (1)
Посмотреть все анекдоты