Главная » Статьи » Мои статьи |
GUI Architectures Графические пользовательские интерфейсы стали привычной частью пейзажа разработки ПО, как для пользователей, так и для разработчиков. Если взглянуть на них с точки зрения дизайна, они представляют с собой особый набор проблем системного проектирования — проблем, у которых есть различные, но похожие решения. Мой интерес в том, чтобы обозначить общие и полезные шаблонные решения, которые могут быть использованы программистами при разработке толстых (rich-client) клиентов. Я видел различные архитектуры как при осуществлении проектных инспекций, так и написанные в более «постоянном» стиле. В этих архитектурах есть полезные решения, однако, описывать их — непростое дело. Возьмем, к примеру, Model-View-Controller. Это решение часто воспринимается как шаблон, но я не вижу особой пользы воспринимать его, как шаблон, хотя бы потому что идеи, в него заложенные, различны по своей сути. Разные люди читают про MVC в различных источниках и воспринимают его идеи по-разному, но называют эти идеи одинаково — «MVC». Это приводит к замешательству и непониманию MVC, будто бы люди узнавали про него через «сломанный телефон». В этой работе я хочу привести некоторое количество интересных архитектурных решений и описать свое видение их самых интересных свойств. Надеюсь, что объясню все в понятном стиле. В некотором роде, вы можете воспринять эту работу как экскурс в историю различных решений программирования UI в течение нескольких лет. Однако, я должен вас предостеречь. Понимание архитектур не простое дело, особенно когда многие из них изменяются или умирают. Прослеживать некоторые идеи еще сложнее, потому что разные люди видят в них свое, отличное от того, что видят другие. В частности, я не провел глубокого и тщательного анализа тех архитектур, которые буду описывать. То, что я сделал, можно обозначить как общее описания дизайнов систем. Если я что-то пропустил — это значит, что я об этом просто не знаю. Поэтому, не воспринимайте мои описания, как руководство. Более того, некоторые вещи я специально оставляю упрощенными, если они незначительны. Помните, что моя основная задача — описать решения задачи, а не историю этих решений. (Однако, я немного себе противоречу — в плане того, что у меня был доступ к работающей версии Smalltalk-80, чтобы я мог изучить MVC. Опять же, я не могу сказать, что это исследование было тщательным, но оно позволило мне понять некоторые аспекты решения, которые другие описания объяснить не смогли — что, в свою очередь, отталкивает меня от намерений преподносить свое описание других архитектур как единственно верное. Если вы хорошо знакомы с какой-либо из таких архитектур и видите, что я в чем-то важном не прав или что-то упустил, то я бы хотел об этом знать. Еще я думаю, что более тщательный анализ того, про что я буду говорить, послужит хорошим предметом изучения в ВУЗах.)
(Фаулер очень рьяно оперирует понятием control, что можно оставить как «контрол» или перевести как «элемент управления». Увы, в русском языке нет слова «контрол» (даже несмотря на то, что оно повсеместно используется в сленге), и, чтобы не мучить вам глаза, далее я буду называть элементы управления просто «элементами». — прим. перев.) Я начну это исследование с архитектуры, которая сама по себе проста и хорошо знакома для большинства разработчиков. У нее нет общего обозначения, поэтому в целях общих правил этой работы, я буду называть ее «Формы и элементы». Эта архитектура хорошо известна прежде всего потому, что она предоставлялась средами разработки клиент-серверных приложений, вроде Visual Basic, Delphi, Powerbuilder. Несмотря на то, что она отвергается такими фанатами крутых архитектурных решений, как я, ее все равно продолжают повсеместно использовать. Для того, чтобы ее понять (и понять другие архитектурные решения), я буду использовать общий для всех пример. В Новой Англии, где я живу, существует государственная программа слежения за количеством мороженого в воздухе. Если концентрация слишком мала, это означает, что мы едим слишком мало мороженого, что, в свою очередь, представляет большой риск для нашей экономики и общественного порядка. (Мне нравится использовать примеры не более реальные, чем вы находите в других книгах, подобной этой). Чтобы следить за нашим мороженым, во всех штатах Новой Англии правительство построило специальные станции слежения. Используя сложную атмосферную модель, департамент назначает целевое (target) значение для каждой станции. После этого персонал отправляется на станции производить оценку концентрации мороженого. UI ниже позволяет им выбрать станцию и ввести дату замера (date) и фактическое значение (actual) концентрации. Система высчитывает отклонение (variance) между целевой и фактической величиной. Более того, если фактическое значение меньше, чем 90% от целевого, отклонение подсвечивается красным, а если больше, чем 105%, то зеленым.
Рисунок 1: UI, который я буду использовать для примера Из этого представления можно выделить две важных детали. Форма (form) является специфичной для приложения, но она использует элементы (controls), которые являются общими для других форм. Большинство сред разработок GUI обладают неким набором общих элементов, которые можно использовать при разработке приложений. Мы имеем возможность создавать свои элементы (и это хорошая идея), однако, формы приложения и повторно используемые элементы все равно друг от друга отличаются. Другими словами, созданные элементы могут быть использованы во множестве различных форм. Форма обладает двумя основными обязанностями:
Элементы отображают данные — в нашем случае, это чтение. Данные, весьма вероятно, приходят откуда-то из другого места. Для нашего случая предположим, что из БД SQL, поскольку она является основным источником данных для упомянутых сред разработки. В большинстве случаев, в приложении существует три копии используемых данных:
Реализация привязки данных является достаточно сложным занятием, потому что вам нужно избегать таких циклов, например, где изменение элемента изменяет набор данных, который обновляет элемент, который обратно обновляет набор данных, который вновь обновляет элемент… Поток использования (flow of usage) помогает избежать таких циклов — мы загружаем данные из состояния сессии в состояние экрана только тогда, когда экран открывается, после этого любое изменение экрана распространяется обратно в состояние сессии. Обновлять состояние сессии тогда, когда открывается экран — необычно и не нужно. В результате, привязка данных может быть не полностью в обе стороны — она может быть ограничена начальной загрузкой данных и обработкой изменений экрана в состояние сессии. Привязка данных, вообще говоря, реализует большинство функциональности клиент-серверного приложения. Если я изменю значение фактической концентрации, значение в колонке обновится. Даже выбор другой станции вызовет изменение выбранной записи в наборе записей, что, в свою очередь, заставит другие элементы обновиться. В основном, описанное поведение уже реализовано разработчиками каркасов приложений, которые предусмотрели и предоставили средства быстро и несложно удовлетворить основные нужды программистов. В частности, одним из способов является явная установка некоторых характеристик элементов управления, которые обычно называют «свойствами». Элемент читает строковое название колонки набора данных, которое было указано разработчиком через простой редактор свойств и привязывается к ней. Использование привязки данных, с нужной параметризацией, может помочь вам реализовать почти всю функциональность приложения. Однако, привязка данных не может реализовать ВСЮ функциональность — почти всегда в приложении существует логика, которая не попадает под опции параметризации. В нашем случае, расчет отклонения представляет собой пример того, что не может быть реализовано через привязку данных — из-за того, что такая функциональность специфична для приложения и реализуется в самой форме. Для того, чтобы ее реализовать, форма должна знать, когда пользователь закончил ввод значения фактической концентрации, а это, в свою очередь, значит, что элемент управления должен вызвать какое-то поведение формы. Такая логика подразумевает инверсию управления (Inversion of Control). (в оригинале «This is a bit more involved than taking a class library and using it through calling it as Inversion of Control is involved.» — прим. перев.) Существуют различные методы решения указанной проблемы. Обычно, среды разработки клиент-серверных приложений обладают системой представления событий. Каждый элемент управления имеет список событий, которые он может запускать. Любой внешний объект обладает возможностью сказать элементу, что его интересует событие. В этом случае, когда событие элемента произойдет, элемент передаст управление такому объекту. По существу, данное описание всего лишь переформулировка шаблона Observer, где форма следит за элементом. Каркас приложения позволяет разработчику формы написать код в методе, который будет исполнен после возникновения события. То, каким образом возникает связь между этим методом и событием, зависит от конкретной платформы и не важно в данном случае. Важно то, что такой механизм существует и он работает. Когда форма получила управление, она может делать все, что ей нужно. Она может выполнить какие-то действия, изменить элементы управления, и, основываясь на привязке данных, провести сделанные изменения обратно в состояние сессии. Такой механизм нужен еще и потому, что привязка данных не всегда доступна. В мире очень много элементов управления окнами и не все из них поддерживают привязку. Если привязки нет, то заниматься синхронизацией данных между состояниями должна форма. В частности, она может сама вытащить данные из набора данных и уложить их в элементы управления. Когда требуется сохранить данные обратно, она может сделать это таким же образом по событию нажатия кнопки «Сохранить». Давайте посмотрим, каким образом будет происходить редактирование текущего значения концентрации, в случае, когда доступна привязка данных. Форма хранит ссылки на элементы управления. Для каждого элемента будет своя ссылка, однако мне интересны только текстовые поля для фактического значения, значения отклонения и целевого значения.
Рис. 2: Диаграмма классов для форм и элементов Текстовое поле объявляет событие, когда изменился его текст. На этапе инициализации форма собирает себя и подписывается на событие, привязывает свой метод к нему — вот, actual_textChanged.
Рисунок 3: Диаграмма последовательности изменения текста. Когда пользователь изменяет значение фактической концентрации, текстовое поле запускает свое событие и, используя особую магию каркаса приложения, выполняет метод формы actual_textChanged. Этот метод получает фактическое и целевое значение из элементов формы, производит вычисления и устанавливает отклонения в текстовое поле разницы. Так же он вычисляет, каким цветом нужно подсветить полученное значение и подсвечивает его. Теперь можно подвести итоги:
Источник: http://www.rusdoc.ru/articles/18358/ | |
Просмотров: 315 | | |
Всего комментариев: 0 | |