Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
107
Добавлен:
02.05.2014
Размер:
6.34 Mб
Скачать

Часть II

Основные подходы к разработке приложений

Теперь, когда вы имеете общее представление об Ajax, пора рассмотреть основные способы разработки приложений. Наша задача — создать работоспособную, надежную программу, простую в сопровождении, которая предоставляла бы пользователю удобный интерфейс. В главе 4 мы рассмотрим вопросы создания клиентского кода и постараемся добиться, чтобы средства CSS, HTML и JavaScript как можно меньше зависели друг от друга. Глава 5 посвящена взаимодействию клиента и сервера.

Web-страни

п

Организация сложного кода пользовательского интерфейса

Использование образа разработки "модель-представление-контроллер'' с JavaScript-кодом

Разделение представления и логики для сопровождаемого кода

" Создание гибкого режима обработки событий

• Генерация пользовательского интерфейса

148 Часть II. Основные подходы к разработке приложений

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

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

4.1. Разновидности архитектуры МУС

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

Однако первоначально архитектура MVC была ориентирована на программы, предназначенные для настольных систем. В Ajax-приложениях существует несколько вариантов ее применения. Рассмотрим эти варианты более подробно.

4.1.1. Применение архитектуры MVC к программам различных уровней

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

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

Внутреннее представление состояний кнопки — например, нажата, отпущена, неактивна, — это модель. В компонентах Ajax она обычно реализуется посредством объекта JavaScript.

Изображение компонента на экране (в случае пользовательского интерфейса он может быть сформирован из нескольких узлов DOM),

Глава 4. Web-страница в роли приложения

149

учитывающее различные состояния, с подсветкой и подсказкой,

это представление.

 

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

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

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

Таким образом, архитектура MVC не обязательно должна быть привязана к знакомому всем сценарию Web-сервера. Обратимся к Web-браузеру.

4.1.2. Применение архитектуры MVC к объектам, присутствующим в среде браузера

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

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

Если вы вспомните традиционное применение MVC для создания серверных программ (см. главу 3), то легко сделаете вывод, что в типичном Ajaxприложении можно выделить по крайней мере три уровня использования

150 Часть II. Основные подходы к разработке приложений

Рис. 4.1. Архитектура "модель-представление-контроллер" в применении к объекту, представляющему дерево.

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

Рис. 4.2. Архитектура "модель-представление-контроллер", применяемая

к клиентской части приложения Ajax. На этом уровне контроллером является JavaScript-код, связывающий пользовательский интерфейс с бизнес-объектами

Глава 4. Web-страница в роли приложения 151

Рис. 4.3. Вложенная архитектура MVC

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

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

4.2. Представление в составе Ajax-приложения

С точки зрения JavaScript-приложения, доставленного браузеру в начале работы, представлением является отображаемая страница, состоящая из элементов DOM, основой для воспроизведения которых является HTMLразметка или действия программы. О принципах программной обработки элементов DOM см. в главе 2.

152 Часть II. Основные подходы к разработке приложений

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

Если над приложением работает команда разработчиков, то представление становится той областью, где сталкиваются различные интересы. Интерактивные средства Ajax-интерфейса определяют не только программисты, но также дизайнеры и художники. Предлагать дизайнеру написать код или привлекать программиста к рисованию — явно бесполезная затея. Даже если кто-либо имеет две специальности и выступает при работе над приложением в двух разных ролях, желательно, чтобы в каждый момент времени он занимался одной конкретной задачей.

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

Вглаве 3 мы описывали действия по структурированию Web-страниц,

врезультате которых коды CSS, HTML и JavaScript располагались в разных файлах. Если рассматривать лишь саму Web-страницу, такое разделение соответствует принципам MVC. Здесь таблицы стилей выступают в роли представления, a HTML/DOM являются моделью. В данном случае средства воспроизведения страницы являются "черным ящиком", а коды HTML

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

4.2.1. Отделение логики от представления

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

<div class='importButton'

onclick=1importData("datafeed3.xml", raytextbox.value);'/>

Сделав это, мы "жестко" закодировали бизнес-логику в составе представления. Что такое datafeed3? Как обрабатывать значение mytextbox. value? Почему функции importData () передаются два параметра и каково их назначение? Дизайнер должен знать об этом.

Функция importData () относится к бизнес-логике. Согласно принципам MVC, представление и модель не должны непосредственно взаимодействовать друг с другом, поэтому они разделены дополнительным уровнем. Предположим, что мы переписали элемент div следующим образом:

Глава 4. Web-страница в роли приложения 153

<div c l a s s = ' i m p o r t B u t t o n ' o n c l i c k = ' i m p o r t F e e d D a t a ( ) ' / >

Теперь, если мы определим обработчик события так, как показано ниже, параметры будут инкапсулированы не в анонимном обработчике, а в функции importFeedData().

function importFeedData(event){ importData("datafeed3.xml", mytextbox.value);

}

Такой подход позволяет использовать обработчик в любом месте программы, разделяя функциональные возможности и следуя принципу DRY (напомним, что данная аббревиатура означает "don't repeat yourself" — не повторяться).

Контроллер пока еще остается встроенным в HTML-код, что может стать источником проблем в больших приложениях.

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

<div class='importButton' id='dataFeedBtn'>

Приведенный ниже код надо включить в функцию обратного вызова window, onload.

var dfBtn=document.getElementById('dataFeedBtn') ; dfBtn.onclick=importFeedData;

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

Добавление обработчиков событий с помощью CSS

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

Листинг 4.1. Файл musical.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtmll/DTD/xhtmll-strict.dtd">

<html> <head> <title>Keyboard</title> <link rel='stylesheet1 type='text/ess1 href='musical.css'/> <script type='text/javascript' src='musical.js'X/script> <script type='text/javascript'> window.onload=assignKeys; </script> </head>

<body>

<div id='keyboard' class='musicalKeys'> <! О — Клавиши на "клавиатуре" —> <div class='do musicalButton'X/div>

154 Часть II. Основные подходы к разработке приложений

<div class='re musicalButton'x/div> <div class='mi musicalButton'X/div> <div class='fa musicalButton'x/div> <div class='so musicalButton'x/div> <div class='la musicalButton'x/div> <div class='ti musicalButton'x/div> <div class='do musicalButton'x/div>

</div> <div id='console' class='console'> </div> </body> </html>

В декларации DOCTYPE МЫ указали определение Strict лишь для того, чтобы показать, что такое решение возможно. Элементу keyboard присвоен уникальный идентификатор, но в дескрипторах, соответствующих отдельным клавишам, идентификатор отсутствует. Заметьте, что для элементов, представляющих клавиши О, указаны два класса. Класс musicalButton — общий для всех клавиш, а второй класс позволяет различать их. Соответствующие стили определены раздельно в файле musical.ess (листинг 4.2).

Листинг4.2.Файлmusical.ess

.body{

background-color: white; } .musicalKeys{

background-color: #ffeOdO; border: solid maroon 2px; width: 536px;

height: 68px; top: 24px; left: 24px; margin: 4px;

position: absolute; overflow: auto;

} .musicalButton{ border: solid navy lpx; width: 60px;

height: 60px; position: relative; margin: 2px;

float: left;

}

.do{ background-color: red; }

.re{ background-color: orange; }

.mi{ background-color: yellow; }

.fa{ background-color: green; }

.so{ background-color: blue; }

.la{ background-color: indigo; }

.ti{ background-color: violet; } div.console{

font-family: arial, helvetica; font-size: 16px;

color: navy; background-color: white; border: solid navy 2px; width: 536px;

Глава 4. Web-страница в роли приложения 155

height: 320px; top: 106px; left: 24px; margin: 4px;

position: absolute; overflow: auto;

}

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

Связывание обработчиков событий с элементами

JavaScript-код, показанный в листинге 4.3, связывает обработчики событий с клавишами.

Листинг4.З. Файл musical, js

function assignKeys(){

// Получение родительского элемента div

var keyboard=document.getElementById("keyboard");

//

Перечисление дочерних элементов

 

var

keys=keyboard.getEleraentsByTagName("div");

if

(keys){

 

for(var i=0;i<keys.length;i++){

 

 

var

key=keys[i];

 

 

var

classes=(key.className).split("

" ) ;

 

if

(classes && classes.length>=2

 

 

SS

 

 

classes[1]=="musicalButton"){

 

 

var note=classes[0];

 

 

// Добавление атрибута

 

 

key.note=note;

 

 

key.onmouseover=playNote;

 

J

}

 

 

}

 

 

 

}function playNote(event){

//Извлечение дополнительного атрибута var note=this.note;

var console=document.getElementById("console") ;

if (note && console){ console.innerHTML+=note+" . ";

}

}