Войти
 
 
   
 
  
Новости Notes.ру Библиотека Биржа труда Вопрос - ответ Форум Регистрация Поиск О проекте
Разделы
О Notes
Советы
Шаблоны и примеры
Литература
Презентации
 
Всё о задаче AdminP. Часть вторая   Во второй части мы завершаем рассмотрение AdminP. В ней рассмотрены запросы междоменного администрирования и способы управления функциями AdminP с помощью настроек документа сервера, команд консоли сервера, файла Notes.ini и интервалов очистки базы данных. В этой статье предполагается, что вы опытный администратор Domino и прочитали первую часть
О Notes Читать статью
 
Всё о задаче AdminP. Proxy-действия в R5 и Domino 6   Приложение к статье об административном процессе
О Notes Читать статью
 
Всё о задаче AdminP. Часть первая   Перевод классической статьи 2003-его года о задаче административного процесса (AdminP). Очень полезна для понимания работы механизма этой задачи. В первой части статьи описаны компоненты задачи AdminP, как они работают, и как их использование помогает сделать работу администратора Domino проще. Задача AdminP (сакращённо от Administration Process, Административный процесс) работает с базой административных запросов (Administration Requests, admin4.nsf)
О Notes Читать статью
 


Шаблоны и примеры

Главная   Библиотека   Шаблоны и примеры

Использование паттерна MVC в модальных диалоговых окнах

Использование паттерна MVC в модальных диалоговых окнах
Василий Соляник

Вступление
Цель данной статьи: рассмотреть возможность применения одного из паттернов – паттерна MVC при проектировании модальных диалоговых окон.
Замечание 1. В статье будет рассмотрена разработка систем под «толстого клиента» - клиента Lotus Notes.

Теория
Продолжая тему первой статьи о пользе ООП (>>>), хочу попробовать подробнее рассмотреть один из паттернов MVC. Несмотря на то, что в книге 1 этот паттерн таковым не назван, всё же, мне кажется, что об этом способе организации классов можно говорить как о паттерне. Фактически можно сказать, что это один из древнейших паттернов. Можно без труда найти довольно большое количество статей подробнейшим образом описывающих его, поэтому опишем лишь вкратце, в чём суть самого паттерна.
Предлагается разделить визуальную часть (View), часть, обрабатывающую действия пользователя (Controller), и те данные, над которыми производятся действия (Model). Отсюда и название MVC (Model, View, Controller). Среди достоинств данного подхода отметим те моменты, которые, на мой взгляд, наиболее интересны в этом паттерне:

  • подобное разделение позволяет более независимо менять входящие в паттерн элементы.
  • возможность повторного использования в модели существующих классов (тех же оберток)
  • возможность максимально сосредоточить логику работы модального окна в одном месте (т.е. в контролере)
Реализация MVC в построении модальных окон в Lotus
Замечание 2. Для простоты изложения будем иногда называть модальное окно инструментарием
Особенностей реализации немного:
  • Работу над значениями в полях (помещение и получение) мы заключаем во View.
  • Код в кнопках, а также всю логику, которую мы хотим реализовать на событиях формы, – помещаем в Controller (т.е. это вызовы соответствующих методов)
  • Ну а Model – хранит данные, которые мы обрабатываем и отображаем.
  • Для большей удобности – предлагается использовать класс Center (простенькая реализация паттерна Mediator). Этот класс инициирует и содержит ссылки на экземпляры классов данной системы.
  • Также для удобства предлагается использовать класс-родитель для каждого из классов MVC. В этом родительском классе содержится только один приватный метод getCenter, который возвращается ссылку на экземпляр класса Center. Таким образом, каждый участник системы может получить доступ к другому участнику системы. (Хотя тут надо сказать, что в большинстве случаев, например, View нет необходимости иметь доступ к Controller’у. Но, тем не менее, применение Center упрощает систему).
  • В Global-declare создаем функцию, которая содержит статическую переменную – экземпляр класса Center.
В результате, например, код на кнопке Ok будет таким:
Call  getStaticPropToolCenter().getController().closeTrue()

Замечание 3. Базу, содержащую пример рассматриваемого материала, можно скачать >>>
Я обычно копирую форму-шаблон (в базе она называется ru.KB.F.md.(Repository.MVC)) и переименовываю классы (заменяя MVC на более подходящее для решения задачи). Здесь, конечно, спорная ситуация. Возможно, эти каркасные классы можно было вынести в некую общую библиотеку и наследовать уже от них. Но мне кажется, что это лишь усложнит использование, т.к., например, класс Model почти всегда уникален для каждого инструментария. Поэтому для обращения к нему через Center будет необходимо делать нисходящее опасное преобразование. К тому же, сами классы в каркасе очень просты. Можно сказать, что это классы-интерфейсы, на основе которых уже создаются конкретные классы в каждом инструментарии.
А вот для вызова инструментария можно применить иерархию классов. Создать абстрактный класс, который реализует часть функционала, общего для всех инструментариев, как-то: создание экземпляра NotesDocument (в контексте которого будет выполняться модальное окно), вызов метода класса NotesUIWorkspace.dialogBox с нужными параметрами. В прилагаемой базе приводится пример такого класса. В конкретном классе, который будем наследовать от этого абстрактного класса, мы добавим методы, с помощью которых будем передавать значения между текущем NotesDocument и тем, в контексте которого работает модальное окно (см. форму TEMP.test и код на кнопке test).

О границах ответственностей между частями MVC
Попробуем подробнее рассмотреть составляющие MVC, используя пример (базу, содержащую пример, можно скачать >>>).
Model (Модель) – хранит, предоставляет доступ и позволяет изменить те данные, которыми мы манипулируем в системе. Эти данные могут быть представлены отдельными классами. Так в примере есть класс PropItem, который определяет способ манипуляции данными вида key=value. А также класс PropItemCollection, с помощью которого мы манипулируем коллекцией экземпляров класса PropItem (например методы addItem, removeItem). Класс Model содержит два экземпляра класса PropItemCollection – один экземпляр для невыбранных пользователем ключей, другой – для выбранных.
Еще у класса PropItem есть методы, возвращающие текстовое представление класса:
  • getFormat – возвращает формат хранения, т.е. то, что мы хотим в итоге получить из инструмента (строка вида: key=value)
  • getDisplay() - возвращает представление на экран в виде, необходимом в инструментарии для работы (строка вида: text = value | key)
Здесь надо отметить, что:
Замечание 1. То, что класс PropItem имеет методы, возвращающие внутреннее представление класса, не нарушает принцип MVC, т.к. сам класс не знает, где и как это представление будет отображаться.
Замечание 2. Мы, например, можем вынести формирование визуального отображения класса PropItem во View или же в отдельный класс (это имеет смысл делать, если таких визуальных представлений несколько). Но в этом случае мы должны будем предоставить интерфейс доступа к внутренним данным класса PropItem (например, getValue, getKey).

View (Представление) – отображает данные из Модели, а также предоставляет методы для получения данных, введенных пользователем. Несмотря на то, что ответственность Представления в целом ясна, границы этой ответственности не совсем четкие.
Так, например, мы можем не давать возможность Представлению обращаться к Модели, взвалив всю работу по передаче данных между Моделью и Представлением на Контролер, например:
Представление Контролер
Function showDateA( val1, val2 )
      meDoc.Field1 = val1
      meDoc.Field2 = val2
End Function

val1 = getCenter().getModel().getDateA1()
val2 = getCenter().getModel().getDateA2()
… (доп. обработка значений)
Call getCenter().getModel().showDateA( val1, val2 )

А можем дать возможность Представлению «напрямую» забирать данные из Модели, например:
Представление Контролер
Function showDateA()
      meDoc.Field1 = getCenter().getModel().getDateA1()
      meDoc.Field2 = getCenter().getModel().getDateA2()
End Function
 
(в методе, когда мы хотим отобразить данные в Представлении)

Call getCenter().getModel().showDateA()

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

Еще одна особенность возникает, когда мы хотим в инструментарии повторно использовать уже существующие классы-обёртки. Такие классы обычно заключают в себе две сущности: Модель и Представление. И вопрос – где лучше их хранить (точнее, где лучше экземпляры этих классов). В большинстве случаев – нет существенной разницы. Но лучше всего их хранить в одном месте (либо в Модели, либо в Представлении), т.к. зачастую еще бывает необходимо обмениваться данными между ними.


Controller (Контролер) – несет ответственность за взаимодействие пользователя с инструментарием, т.е. при нажатии кнопок на форме или срабатывания интересуемого нас события – вызывается соответствующий метод в Контролере (исключение – событие postOpen, где еще происходит вызов метода init(NotesUIDocument) класса Center)
Т.е. код в действиях и событиях будет примерно таким:
Call getCenter().getController().getMethod…( param… )
(рекомендую использовать именно такой подход – это не позволит коду «расползтись» по форме инструментария, и весь код будет сосредоточен в Контролере)

Надо сказать, что границы Контролера также нечёткие. Часть логики может содержаться в Модели (а также в содержащихся в модели классах-обёртках), а иногда и в Представлении (например, некоторые простые преобразования). Здесь всё зависит от разработчика – что он посчитает более выгодным использовать для данного инструментария.

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

Создание сложных инструментариев
В целом можно сказать, что использование шаблона MVC не должно вызвать трудности при реализации модальных окон различной сложности. Однако, при создании сложных инструментариев, с большим количеством полей, действий, сложной логикой – классы MVC могут раздуваться, или же будет увеличиваться количество вспомогательных классов.
В некоторых случаях удаётся упростить систему, если выделить тот код, который манипулируют одной частью инструментария, в один класс. Т.е. взять методы из классов MVC, которые работают с некой независимой частью инструментария, и вынести их в один класс – получить как бы локальный класс-обёртку, инкапсулирующий логику работы определенной части системы. Проделав это со всеми частями инструментария, которые можно выделить как независимые, подобные преобразования кода, мы в итоге получим:
  • набор локальных классов-оберток, которые манипулируют логикой работы своих частей инструментария
  • MVC, так называемого, первого уровня – манипулирующий логикой работы инструментария в целом через созданные локальные классы-обертки.

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


Пример
Сам пример приведен в прилагаемой базе. Поэтому я лишь немного опишу то, что в этой базе.

Формы
ru.KB.F.md.(Repository.MVC)Эта форма с классами, которые можно использовать как каркас MVC. С нее сделана следующая форма:
ru.e-sed.F.md.(Attribute.Edit)В этой форме-инструменте релизован пример редактирования набора строк вида:
ключ=значение
TEMP.testЗдесь вызывается модальное окно
Еще в базе есть несколько вспомогательных библиотек.

По поводу примера - хочу обратить Ваше внимание на статью Николая Каретникова (>>>). В ней он говорит о конкретной применимости MVC и приводит более развернутое описание инструментария, построенного по принципу MVC.

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

Благодарности
В заключении мне хочется выразить благодарность:
Каретникову Николаю, Акулову Дмитрию, Рябчикову Владимиру и Норкину Николаю за огромную помощь в написании этой статьи.

Литература.
(Внимание! Приведенные ниже ссылки на книге не реклама! Это просто первые ссылки при поиске в google.com по фамилиям авторов или по названиям книг).

[1]

Приемы объектно-ориентированного проектирования. Паттерны проектирования
Гамма, Хелм, Джонсон, Влиссидес

http://www.books.ru/shop/books/8451

[2]

Применение шаблонов проектирования. Дополнительные штрихи
Джон Влиссидес

http://www.williamspublishing.com/Books/5-8459-0393-9.html

[3]

Применение шаблонов Java.
Стивен Стелтинг, Олав Маассен

http://epokupka.ru/tov/primenenie-shablonov-java-biblioteka-professionala-_1

Материалы по теме на Notesnet.ru
О пользе ООП при проектировании систем на платформе Lotus Notes/Domino >>>
Пример UI элемента на основе паттерна MVC >>>
Паттерны. Практикум программирования >>>
 
  Опубликовано — 06/22/2007 |    



Добавить комментарий
Имя * :
e-mail
Комментарий * :
Код подтверждения * :

Мероприятия
Пресс-релизы
Биржа труда
Последнее на форуме
 
А так же:
Как удалить профиль?
16.04.2016 00:08:51
Скопировать в буфер поле документа
24.05.2015 08:55:52
Импорт DXL-описания документов в Lotus Domino. Одноимённые поля
16.04.2015 16:49:58
 
© LOGOSPHERE.RU