SlideShare uma empresa Scribd logo
1 de 19
FlexPure MVC архитектура для приложений
             enterprise уровня




Описание:
1. Сначала мы вспомним основные составляющие микроахитектурыPureMVC, используя презентацию
   SamuelAsherRivello.
2. Далее рассмотрим структуру и задачи, возникающие при использовании PureMVC в больших проектах.
      a. Разновидности и жизненный цикл элементов системы
      b. Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми
          элементами.
3. «Страничная» архитектура для PureMVC проекта:
      a. Управление View компонентами в «страничной» архитектуре:
              i. отложенное (deferred) создание,
             ii. расположение в иерархии DisplayObjects- слоты, медиаторы-слотхолдеры и их
                 взаимодействие с медиаторами-клиентами.
      b. Жизненный цикл «страницы», дескриптор «страницы»
      c. Прелоадер страницы

4. Взаимодействие View Components и Mediators
      a. Шаблон «страницы»
      b. Интерфейс «страничного» View Component
      c. Обмен данными между медиатором и View компонентом.
      d. Состояние «редактирования» (Editing state)
      e. Обработка нажатий кнопок (Buttons)
      f. Обработка других команд (пример – Chevrons)

5. Использование модулей в «страничной» архитектуре.

Требования к слушателям:
знание AS3, жизненного цикла компонентов Flex, PureMVChttp://puremvc.org

Докладчик:
Сергей Шичинов - SergiyShychynov (EPAM)Sergiy_Shychynov@epam.com

Примечание: пункт 4 был исключён из доклада для того чтобы длительность доклада
соответствовала регламенту.

2012-03-24
Основные составляющие PureMVC
(используя презентацию SamuelAsherRivello)

http://www.adobe.com/newsletters/inspire/december2008/articles/article6/index.html

MVC in PureMVC




Схема взаимодействия компонентов PureMVC для выполнения элементарной операции:

-   Внешний вид компонента HelloGoogle – кнопка и текстовое поле для сообщения
-   Последовательность элементарных действий выполняемых при нажатии кнопки
-   Положение этих действий на диаграмме PureMVC
Основные задачи, возникающие при использовании PureMVC в больших
проектах.
Когда речь идет о приложение enterprise уровня, то это означает что они БОЛЬШИЕ. То есть имеется
БОЛЬШОЕ количество РАЗНЫХ форм и компонентов, которые необходимо будет использовать в разных
ситуациях и в разное время. И речи о том, что все элементы будут созданы одновременно или заранее быть
не может. Более того – было бы неплохо, чтобы и грузить их все сразу не требовалось.

Рассмотрим несколько разных «видов» гипотетического большого приложения.
Среди всего UIбольшого приложения можно выделить элементы (подсистемы):

1. Которые постоянно находятся на экране и доступны для взаимодействия.
2. Которые могут вызываться пользователем на экран по желанию и ведут себя относительно независимо
   от других элементов UI.
3. Которые имеют отношение к текущей операции, выполняемой пользователем, показываются на экране
   когда он начинает выполнять эту операцию и будут убраны с экрана когда он эту операцию
   завершит.Причем таких циклов появления и исчезновения с экрана может быть много. Этот третий тип
   подсистем мы будем в дальнейшем называть страницами – Pages.
И если операции по обслуживанию жизненного цикла (описанные далее) для компонетов 1 и 2 типа
можно выполнить один раз (например в StartupCommand), то выполнение всех нижеперечисленных
действий для компонентов подсистем 3-его типа является рутинной операцией и нуждается в
автоматизации.

Жизненный цикл элементов системы
Каждая подсистема 3 типа («страница») может состоять из одного или нескольких видимых элементов,
функционирующих совместно в одном промежутке времени. И для функционирования любой отдельной
подсистемы нашей большой системы нам будет необходимо:

1. Создать (инстанциировать) и разместить на экране (в иерархии DisplayObjects) необходимые компоненты
   - ViewComponents. (Здесь и дальше компонентом будет называться видимый элемент, занимающий
   место в иерархии DisplayObjects.)
2. создать и зарегистрировать необходимые медиаторы – Mediators.
3. связать медиаторы с соответствующими компонентами
        a. медиаторы должны иметь ссылки на свои компоненты, для того чтобы передавать в них данные и
           совершать действия
        b. медиаторы прослушивают события – Events от компонентов для того чтобы узнать что нужно что-
           то делать
4. зарегистрировать необходимые для работы подсистемы комманды – Commands (связать их с
   Notifications),
5. создать и зарегистрировать необходимые для работы прокси–Proxy,
6. отобразить в наших компонентах валидные данные и обеспечить взаимодействие
        a. Как правило, эти данные загружаются извне (с сервера). Это может занять определенное время.
           Эти данные возможно не получится загрузить в результате ошибки. И возможно имеются некие
           политики безопасности, которые в зависимости от того какие именно данные хочет увидеть
           пользователь, могут не разрешить ему увидеть эти данные – и мы не узнаем о том разрешено это
           или нет, пока не получим ответ с сервера.
           Во всех этих случаях неразумно показывать на экране новые компоненты, еще не заполненные
           данными, до того как эти данные будут получены с сервера. Это процесс мы будем называть
           предзагрузка – preloader.
        b. Во время работы пользователя с подсистемой, коммуникация с сервером обеспечивается по
           стандартной схеме изложенной выше.
c. Отдельный вопрос – это обработка ошибок (серверных) – в зависимости от типа ошибок мы может
          либо дальше продолжать оставаться на странице, либо потребуется обновить ее, либо придется
          покинуть ее.
7. После того как пользователь завершил операцию нам необходимо корректно освободить ресурсы
   системы от текущей «страницы» (очевидно перед тем как будет открыта следующая).
       a. Удаление «актеров» PureMVC (медиаторов)
                i. «отписать» медиаторы от системы (unregister) чтобы они не прослушивали больше
                   нотификейшены.
               ii. Можно также удалять медиаторы, но можно сохранять их в «кэше» до следующего
                   использования.
              iii. Команды тоже можно «отписать» от системы, но это не обязательно.
              iv. Некоторые прокси можно было бы тоже отписывать от системы и удалять, но обычно этого
                   не нужно. И даже вредно.
       b. Отписывание медиаторов от events, которые они прослушивали от компонентов.
       c. Удаление видимых компонентов.
          Вообще говоря, операция создания компонента и добавления его в DisplayList гораздо более
          ресурсоемкая, чем сделать невидимый компонент – видимым. Поэтому для увеличения
          перформанса и для того чтобы видимые элементы появлялись более плавно вместо удаления
          компонентов лучше делать их невидимыми.
       d. Если в процессе выполнения операций были загружены какие-то большие данные и ссылки на них
          сохранились в компонентах или «актерах» PureMVC – то нужно их очистить, чтобы позволить
          GarbageCollector –у освободить память.


Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми
элементами.
Как известно видимые элементы – компоненты флекса не создаются мгновенно по запросу. Как правил от
момента создание экземпляра компонента, установки его свойств и добавления его в иерархию
DisplayObjectsпроходит некоторое время и несколько этапов, прежде чем событие «creationComplete»дает
нам знать, что компонент и все его подкомпоненты полностью созданы и готовы к работе.
До этого момента медиатор, даже если и будет иметь ссылку на компонент, не сможет полноценно с ним
работать.


DefferedMediator

Решает проблему асинхронного создания компонентов. Откладывает вызовы initialize и activate до
момента, когда компонент будет создан и инициализирован. А потом еще откладывает update до
момента, когда все медиаторы из списка будут активированы.



Constructor() – чистый конструктор (не выполняющий никаких действий)

* Override it to complete setup mediator properties and associate mediator
* with the View Component. Use setupMediator function to do most of the tasks.
function create():void

* The method is called after component <code>creationComplete</code> event.
* Create it to add listeners and make additional view component initialization.
function initialize():void;

* This method is called every time when you show and activate the view component.
* Override it to add additional mediator's and view component's activation.
functionactivate():void;

waitForMediatorsActivation(mediatorNames);

* Override it to update view component in accordance with current viewParams.
* You can process here both stateParams and viewParams.
* Is called after initialize() (after creationComplete event) and
* activate() methods.
function update():void

* Deactivate mediator (remove from pureMVC workflow).
* You can override it to make additional deactivation.
functiondeactivate():void;

* Create it to remove listeners and make additional view component finalization.
functionfinalize():void;



Кто, когда и как создает видимые элементы.
Слоты, медиаторы-слотхолдеры и их взаимодействие с компонентами-клиентами.
Задача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор.

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

SlotViewComponentDescription
viewComponentName:String,
viewComponentSlot:String,
viewComponent:UIComponent


                                                        SlotAMediator
      M1Mediator


                                                медиатор-слотхолдер
      медиатор-клиент                           SlotAMediator получает
      M1Mediator создает                        нотификейшен, адресованный ему
      компонет и отправляет его                 и добавляет в свой слот (ViewStack
      слоту "SlotAMediator" -                   или другой контейнер) новый
      просит его хранить под                    компонет под именем "M1"
      именем "M1"
«Страничная» архитектура для PureMVC проекта
Мы ввели понятие страниц – Pages.
«Страница»– это некоторое множество видимых элементов, функционирующих совместно в одном
промежутке времени. Эти компоненты и обслуживающие их актеры PureMVC совместно создаются, работают
и удаляются.
Выполнением всех этих операций в PureMVC традиционно занимаются команды.
Чтобы не писать отдельные команды для открытия каждой страницы, была создана единая команда
открытия новой страницы ViewPageCommand. Эта команда выполняет все необходимые при открытии
страницы действия в соответствии с переданным ей в качестве входного параметра дескриптором
страницы.
Она работает совместно с PagesProxy, которыйи является хранителем информации обо всех доступных
в системе «страницах» и «состояния» текущей открытой страницы.

Основные задачиPagesProxy:
        - хранение справочника всех страницах в системе
functiongetPageDescription(pageName:String):PageDescription

       - хранение информации о текущей открытой странице (ее имя, дескриптор, стейт, состояние
       редактирование, helpContext и прочее)

Соответственно все страницы имеют уникальное имя
publicclass Pages
{
publicstaticconstABOUT:String = "about";
publicstaticconstADMIN_EMAIL_TEMPLATE_EDIT:String = "adminEmailTemplateEdit";
publicstaticconstDOCUMENT_TRANSLATION:String = "documentTranslation";
…
}
идескрипторы

PageDescription
pageName:String,

preloader:Class, - наследникBasePagePreloader

mediators:Array, - списокклассовнаследониковBaseMediator
proxies:Array = null,
commands:Array = null, - списокCommandDescription(name:String, commandClass:Class)

stateParams:Object = null, - редко встречающиеся дополнительные параметры

pageTitle:String = null,    }   - часто встречающиеся дополнительные параметры
breadcrumbs:Array = null. … }

Примердескриптора страницы:
newPageDescription(Pages.QUESTIONNAIRE,
QuestionnaireAnswerPreloader,
    [QuestionnaireSlotHolderMediator, QuestionnaireAnswerMediator],
    [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy, TimeScaleProxy],
    [
newCommandDescription(SPNotification.FIND_NEW_QUEST, LoadQuestiannairCommand),
newCommandDescription(SPNotification.UPDATE_ASSET_QUEST, UpdateAssetForQuestCommand),
    ],
{questionnaireComponentState: QuestionnaireComponentState.ANSWER},
"Questionnaire Registry"
)


PageNotificationParams
varpageName:String;
varpageState:String;
varid:Number;
varbackPageName:String;
varpreloader:BasePreloaderMediator; - создается и добавляется в процессе открытия страницы


ViewPageCommand
    1. Проверяет наличие дескриптора страницы и при необходимости подгружает модуль содержащий
       страницу. Входными параметрами для открытия страницы являются:
          a. pageDescriptor – находится по имени страницы
          b. stateParams : {} – является дополнительным набором параметров страницы (которые не
             вошли в сам дескрипотор – так как редко используются)
          c. viewParams: PageNotificationParams – дополнительные параметры страницы, заполняемые
             при ее открытии
    2. Создает и регистрирует необходимые прокси (они могут быть нужны прелоадеру)
    3. Создает и запускает прелоадер
          a. load()
          b. validate() + препроцессинг
    4. Если прелоадер «дал добро», то закрывает текущую страницу
          a. отписывает от системы медиаторы
          b. подчищает «временные» данные (на вью компонентах и медиаторах!)
          c. отписывает медиатор от events компонентов
          d. добавляет ссылку на прелоадер с загруженными и подготовленными данными во viewParams
    5. Регистрирует команды
    6. Создает (или достает из кеша) медиаторы, передает им значения stateParams и viewParams и
       регистрирует их в системе.
          a. Если медиаторы создаются то это делается в следующем порядке
                   i. Конструктор
                  ii. Setup params (stateParamsиviewParams)
                 iii. create()
          b. если достается из кеша, то просто Setupparams (stateParams и viewParams)
    7. Активирует медиаторы. В процессе активации медиаторы должны создать свои компоненты,
       разместить их в иерархии DisplayLists, сделать видимыми и подписаться на необходимые events.
    8. После активации всех медиаторов вызывается update()



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

Фрагмент кода вызова прелоадера при открытии страницы
if(pageDesc.preloader != null) {
setLoadingState(true);
registerProxies(); // for preloadin purposes
varpreloaderMediator:BasePreloaderMediator = new (pageDesc.preloader)();
preloaderMediator.viewParams = params;
preloaderMediator.stateParams = pageDescriptor.stateParam;
preloaderMediator.callback = executeAfterPreload;
preloaderMediator.load();


BasePreloaderMediator
varstateParams:Object;
varviewParams:PageNotificationParams;
* Override it to create more preloader parts. You can use viewParams and stateParams.
function load():void
{
//...
addDelegatePreloaderPart("YYYid", ResourceTypeDelegate.instance.getResourceTypeById(id));
//...
addNotificationPreloaderPart("XXXid", XXXResultNotification, XXXFaultNotification);
xxxProxy.load(blablabla);
//...
activate();
}

* Override it to validate loaded data. If ERROR - you have to setup
* preloader.errorKey before returning false value.
function validate():Boolean
{
if(preloader.errorKey == null)
    {
// достаем нужное нам данное и проверяем
getPart("YYYid") – используем для проверки
    }
return (preloader.errorKey == null);
}



Пример прелоадера «детям до 16»
publicclassManageGroupMembershipPreloaderextendsBasePreloaderMediator
{
overridepublicfunction load():void
  {
varid:Number = getID(true);
if(!isNaN(id))
addDelegatePreloaderPart(ContactProxy.CONTACT,
ContactDelegate.instance.getContactById(id) );

addNotificationPreloaderPart(LanguageProxy.PLAIN_LANGUAGE_LIST,
SPNotification.PLAIN_LANGUAGE_LIST_LOADED,
SPNotification.PLAIN_LANGUAGE_LIST_FAILED);

LanguageProxy(facade.retrieveProxy(LanguageProxy.NAME)).getPlainLanguageList();

super.load();
  }

overridepublicfunction validate():Boolean
  {
if(super.validate())
    {
varcontact:Contact = getPart(ContactProxy.CONTACT) as Contact;
if(contact != null&&contact.age< 16)
setPreloaderError("Просмотр этой страницы не разрешен детям до 16");
returnsuper.validate();
    }
}



Модульность
В настоящее время система имеет:
 полторы сотни (150) основных страниц со связанными с ними rollover формами,
 несколько десятков popup-форм
 некоторое кол-во подсистем,
        работающих постоянно на экране,
        вызываемых по требованию пользователя
   или работающий в качестве «демонов» – daemon (ping, systemmessages)
          и«сервисов» (messages, multiple operations, progress indication etc.)

Кодовая база клиентской части проекта включает более 2000 файлов. Из них более 1600 as файлов и
около 400 mxml.

При этом с точки зрения заказчика это все разбито на 8 логических «модулей» и лицензия на
использование каждого из них может покупаться отдельно.

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

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

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

RSLдля этого использовать нельзя, так как для RSLприходилось бы вручную выбирать какие классы включать в эту
библиотеку а какие - нет. Что неприемлемо при колве классов больше 2000.

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

И в разбиении системы на модули очень помогло то, что мы имели большинство функционала, организованного в виде
«страниц». Страницы были использованы как ноды для дерева линковки всех классов, необходимых для работы
текущего модуля.

Таким образом, модуль подгружает ViewPageCommandв момент когда впервые понадобиться страница содержащаяся в
этом модуле. После загрузки модуля (и всех его классов) все PageDescriptors, содержавшиеся в этом модуле добаляются
в список доступных страниц в PagesProxy.


Структура иерархии модулей

       Module – единица компиляции и линковки
       ModuleDescription – содержитполныйнаборвсехPageDescriptorsмодуля
       PageDescriptionsXXX – логически сгруппированные наборы дескрипторов страниц
       moduleDescriptors.xml – справочник, содержащий информацию о том какая страница в каком
       модуле содержится

   flex-include-vo.xml – список всех VO системы для включения в ядро системы (решение проблемы
   регистрации VO для ремотинга)

   Соответствующие ANTскрипты. !!!НИКОГДА не включайте модули из среды FlashBuilder!!!



Проблема регистрации классов для римотинга.
[RemoteClass(alias="com.os.sp.domain.messaging.MessagesGroup")]
publicclassMessagesGroupextendsMessagesGroupBaseimplementsIOSSPMessage{}

Не регистрирует класс, если VOлинкуется через модуль!

Решение проблемы:

   1) вмодуледелаемregisterServerClass(MessagesGroup);

publicstaticfunctionregisterServerClass(classRef:Class):void
{
registerClassAlias(getClassServerName(classRef), classRef);
}

    2) линкуем все VOв ядро системы (flex-include-vo.xml

<?xmlversion="1.0"?>
<flex-config>
<includesappend="true">
<symbol>com.os.sp.domain.administration.authorization.ContactGroupIPRange</symbol>
<symbol>com.os.sp.domain.messaging.MessagesGroup</symbol>
<symbol>com.os.sp.domain.messaging.SmsCostConfig</symbol>
<symbol>com.os.sp.domain.integrity.InvalidRecord</symbol>
<symbol>com.os.sp.domain.reporting.monitoring.GenerationState</symbol>
</includes>
</flex-config>


publicfunctionModuleMain()
{
super();

    _moduleDescription = newModuleDescriptionMain();

//NameUtils.registerServerClass(ContactTask);
//NameUtils.registerServerClass(ReportResponse);

initializeModule();
}


publicfunctionModuleDescriptionMain()
{
super("ModuleMain", [], []
        .concat(PageDescriptionsMain.pageDescriptions)
        .concat(PageDescriptionsMyShadowPlanner.pageDescriptions)
        .concat(PageDescriptionsContacts.pageDescriptions)
        .concat(PageDescriptionsResourcesAssets.pageDescriptions)
        .concat(PageDescriptionsReporting.pageDescriptions)
        );
}

publicclassPageDescriptionsResourcesAssets

{
publicstaticconstcommonBreadcrumbs:Array = [Pages.R_A_VIEW_ROOT_RESOURCES];

publicstaticconstcommonProxies:Array = [ResourceTypeProxy, ParentListProxy,
SessionDataProxy,AssetProxy, ProcessEditProxy, ProcessesListProxy];

publicstaticconstpageDescriptions:Array = [/////////////////////////////////////////////


newPageDescription(Pages.UPDATE_RESOURCE_TYPE,
PageState.ADD_EDIT_VIEW,
ResourceTypeEditPreloader,
Pages.R_A_VIEW_ROOT_RESOURCES,
    [ResourcesSlotHolderMediator, ResourceTypeEditMediator],
    [SessionDataProxy, AssetProxy, ProcessEditProxy],
[
newCommandDescription(SPNotification.FIND_ASSET_FOR_DETAILS, LoadAssetCommand),
newCommandDescription(SPNotification.FIND_ASSET_FOR_EDIT, LoadAssetEditCommand),
],
    {accessArea: AccessArea.RESOURCE_TYPES},
commonBreadcrumbs.concat(),
"page.updateResourceType.title",
"page.updateResourceType.breadcrumbLabel",
null
).addAddPageState(null,
"page.createResourceType.title",
"page.createResourceType.breadcrumbLabel"
).addViewPageState(null,
"page.updateResourceType.viewTitle",
"page.updateResourceType.viewBreadcrumbLabel"
).addLibraryPageState(
Pages.R_A_UPDATE_RESOURCE_TYPE_FOR_LIBRARY
),

newPageDescription(
Pages.QUESTIONNAIRE, PageState.EDIT_VIEW,
QuestionnaireAnswerPreloader, null,
    [QuestionnaireAnswerMediator],
    [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy],
null,
    {questionnaireComponentState:QuestionnaireComponentState.ANSWER},
    [TreeNodeBase.NODE_BIA]
).registerRollover(Rollovers.QUESTIANNAIRE_RECOVERY_SCHEDULE, PageState.ADD_EDIT_VIEW
).registerRollover(Rollovers.QUESTIONNAIRE_ADD_PROCESS, PageState.ADD_EDIT_VIEW
)

] /////////////////////////////////////////////
}

moduleDescriptors.xml

<?xmlversion="1.0"encoding="UTF-8"?>
<Modules>
<Modulename="ModuleMain">
<Pages>
<Pagename="about"/>
<Pagename="myTasksPage"/>
<Pagename="myResponsibilitiesPage"/>
<Pagename="myPasswordPage"/>
</Pages>
<Dependencies/>
</Module>
<Modulename="ModuleAdministration">
<Pages>
<Pagename="adminLogo"/>
<Pagename="adminLanguageEditor"/>
<Pagename="auditTrail"/>
</Pages>
<Dependencies/>
</Module>
<Modulename="ModuleQuestionnaires">
<Pages>
<Pagename="questionnaires"/>
<Pagename="questionnaire"/>
<Pagename="questionnaireTemplates"/>
</Pages>
<Dependencies/>
</Module>
</Modules>


Фрагмент ant-task-а компиляции основного приложения (ядра системы)
<property name="FLEX_INCLUDE_VO_CONFIGURATION" value="${MAIN_SOURCE_FOLDER}/flex-include-vo.xml" />

<mxmlc file="${MAIN_SOURCE_FOLDER}/${ROOT_APPLICATION}.mxml"
output="@{output}.swf"
link-report="${BUILD_FOLDER}/${ROOT_APPLICATION}.${FULL_LINK_REPORT_POSTFIX}"
>
<load-configfilename="${FLEX_LOCAL_CONFIGURATION}"/>
</mxmlc>

Компиляциямодулей
<targetname="compile-modules"if="flex.modular.exist">
<compile-module-simplemoduleName="ModuleAdministration"/>
<compile-module-simplemoduleName="ModuleMessaging"/>
<compile-module-simplemoduleName="ModuleImportExport"/>
</target>

Фрагмент из макроопределения компиляции модуля
<mxmlcfile="${MODULE_SOURCE_FOLDER}/@{moduleName}.@{moduleType}"
output="${BUILD_FOLDER}/@{moduleName}.swf"
load-externs="${BUILD_FOLDER}/@{dependsOn}.${FULL_LINK_REPORT_POSTFIX}"
>
</mxmlc>




Приложение: особенности реализации SlotHolderмедиаторов
Задача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор.

Медиатору известен класс его компонента. При создании медиатора – в методе create() – медиатор создает
инстанс класса вью компонента и отправляет его слот-холдермедиатору чтобы тот поместил его себе в
DisplayList.

protectedfunctionsetupMediator(…)
mediatorName:String = null,
// AUTO – такое же как имя класса – для регистрации в PureMVC

viewComponentReference:Object = null,
// 1) null must be null,
  // 2) component class
  // 3) component instance (descendant of UIComponent)

viewComponentName:String = null, // viewComponent custom name
// AUTO – по имени медиатора без постфикса Mediator
  // будет использовано как id и name в слотхолдере

viewComponentSlot:String = null, // specific slot for register/find viewComponent (if need)

viewComponentInitAction:int = 0 // special init action (0 - no action)
       INIT_NONE:int = 0; // no action

       INIT_FIND_OR_WAITING_FOR_THE_VIEW_COMPONENT:int = 1;
       // find view component with appropriate name in appropriate slot or (in not found)
       // listen for the BaseNotifications.SLOT_VIEW_COMPONENT_CREATION_COMPLETE notification

       INIT_FIND_VIEW_COMPONENT:int = 2;
       // find view component with appropriate name in appropriate slot

       INIT_ADD_TO_SLOT:int = 4;
       // add view component to appropriate slot using appropriate name


overridepublicfunctionlistNotificationInterests():Array
{
return (slots == null)
    ? super.listNotificationInterests()
    : super.listNotificationInterests().concat(
BaseNotifications.SLOT_VIEW_COMPONENT_ADD,
BaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME,
BaseNotifications.SLOT_VIEW_COMPONENT_SHOW,
BaseNotifications.SLOT_VIEW_COMPONENT_HIDE,
BaseNotifications.SLOT_VIEW_COMPONENT_FIND
      );
}

overridepublicfunctionhandleNotification(notification:INotification):void
{
super.handleNotification(notification);
  …
}

privatefunction defaultSlotHolderNotificationHandler(notification:INotification):void
{
if(slots && slots[notification.getType()]) {
vardesc:SlotViewComponentDescription = notification.getBody() as SVCD;
varcomponent:UIComponent;
component = getViewComponentFromSlot(desc.viewComponentSlot, desc.viewComponentName);
switch(notification.getName()) {
caseBaseNotifications.SLOT_VIEW_COMPONENT_SHOW:
FlexUIComponentsUtils.showViewComponent(component, true);
break;
caseBaseNotifications.SLOT_VIEW_COMPONENT_HIDE:
component.visible = false;
break;
caseBaseNotifications.SLOT_VIEW_COMPONENT_ADD:
addViewComponentToInternalSlot(desc);
desc.viewComponent = null; // mark viewComponent as added
break;
caseBaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME:
removeViewComponentFromSlotByName(desc);
break;
caseBaseNotifications.SLOT_VIEW_COMPONENT_FIND:
desc.viewComponent = component;
break;
}}}



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

* Register handler for Notification - works just like addEventListebner.
* It doesn't depend on registerMediator/removeMediator !BE AWARE!
functionaddNotificationListener(notificationName:String, handler:Function):void
{
org.puremvc.as3.core.View.getInstance().registerObserver(
notificationName, new Observer(handler, this) );
}

* Remove Notification handler - works just like removeEventListebner.
* It doesn't depend on registerMediator/removeMediator !BE AWARE!
functionremoveNotificationListener(notificationName:String):void
{
org.puremvc.as3.core.View.getInstance().removeObserver(
notificationName, this );
}

Примериспользования:
* Try to add view component in appropriate external slot. If there isn't
* appropriate slot then start waiting for SLOT_CREATION_COMPLETE.
functionaddViewComponentToExternalSlot():void {
vardesc:SlotViewComponentDescription = newSlotViewComponentDescription
viewComponentName, viewComponentSlot, viewComponentasUIComponent );

varaddNotification:INotification = new Notification(
BaseNotifications.SLOT_VIEW_COMPONENT_ADD, desc, viewComponentSlot);

facade.notifyObservers(addNotification);

if(desc.viewComponent != null) // егобыобнулилиеслибыонбылнайден
    {
addNotificationListener(BaseNotifications.SLOT_CREATION_COMPLETE,
handleSlotCreationCompleteNotificationToAddViewComponent);
    }
}

Mais conteúdo relacionado

Mais procurados

Moxy – реализация MVP под Android. С щепоткой магии
Moxy – реализация MVP под Android. С щепоткой магииMoxy – реализация MVP под Android. С щепоткой магии
Moxy – реализация MVP под Android. С щепоткой магииYuri Shmakov
 
Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...Александр Шамрай
 
C# Web. Занятие 11.
C# Web. Занятие 11.C# Web. Занятие 11.
C# Web. Занятие 11.Igor Shkulipa
 
Role based access-control
Role based access-controlRole based access-control
Role based access-controlAlex Frolov
 
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012Александр Шамрай
 
MVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоватьсяMVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоватьсяYuri Shmakov
 
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...Александр Шамрай
 
Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...metaform
 
Разработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel FirstРазработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel FirstDenis Tsvettsih
 
C# Web. Занятие 13.
C# Web. Занятие 13.C# Web. Занятие 13.
C# Web. Занятие 13.Igor Shkulipa
 
Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Denis Tsvettsih
 
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...Александр Шамрай
 
FFCMS - вводная для пользователя
FFCMS - вводная для пользователяFFCMS - вводная для пользователя
FFCMS - вводная для пользователяzenn1989
 
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...Александр Шамрай
 
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012Александр Шамрай
 
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYYMail.ru Group
 
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Ontico
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Denis Tsvettsih
 
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryUafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryMax Rozdobudko
 

Mais procurados (20)

Moxy – реализация MVP под Android. С щепоткой магии
Moxy – реализация MVP под Android. С щепоткой магииMoxy – реализация MVP под Android. С щепоткой магии
Moxy – реализация MVP под Android. С щепоткой магии
 
Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...Введение в тестирование с использованием закодированных автоматических тестов...
Введение в тестирование с использованием закодированных автоматических тестов...
 
C# Web. Занятие 11.
C# Web. Занятие 11.C# Web. Занятие 11.
C# Web. Занятие 11.
 
Role based access-control
Role based access-controlRole based access-control
Role based access-control
 
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
Визулизация ветвления и объединения в Visual Studio Team Foundation Server 2012
 
MVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоватьсяMVP, Moxy. Как правильно пользоваться
MVP, Moxy. Как правильно пользоваться
 
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
Разработка оптимального ПО - создание раскадровок и сбор отзывов от заинтерес...
 
Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...Создание графического интерфейса пользователя мобильных Android приложений (ч...
Создание графического интерфейса пользователя мобильных Android приложений (ч...
 
Разработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel FirstРазработка WPF приложений в стиле ViewModel First
Разработка WPF приложений в стиле ViewModel First
 
Dw Shark Ru
Dw Shark RuDw Shark Ru
Dw Shark Ru
 
C# Web. Занятие 13.
C# Web. Занятие 13.C# Web. Занятие 13.
C# Web. Занятие 13.
 
Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus Как написать XAML-приложение без Message Bus
Как написать XAML-приложение без Message Bus
 
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...
Проектирование и выполнение ручных тестов с использованием Microsoft Test Man...
 
FFCMS - вводная для пользователя
FFCMS - вводная для пользователяFFCMS - вводная для пользователя
FFCMS - вводная для пользователя
 
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...
Изучение кода с использованием инструментов архитектуры в Visual Studio Ultim...
 
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012Гибкое управление проектами в Visual Studio Team Foundation Server 2012
Гибкое управление проектами в Visual Studio Team Foundation Server 2012
 
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
«Как я научился не волноваться и полюбил Android-MVP», Никита Бартишок, ABBYY
 
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
Moxy. Как правильно пользоваться? / Юрий Шмаков (Arello Mobile)
 
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
Объять необъятное, или как использовать несколько MVVM фреймворков в одном XA...
 
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha DmitryUafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
Uafpug 8 Presentation Puremvc Papervision Gallery Kuriksha Dmitry
 

Destaque

Rồng Bay - Mai-Hương
Rồng Bay -  Mai-HươngRồng Bay -  Mai-Hương
Rồng Bay - Mai-Hươngngoctanbui
 
If you can’t be found you won’t be found final
If you can’t be found you won’t be found finalIf you can’t be found you won’t be found final
If you can’t be found you won’t be found finalAniisu K Verghese
 
maybomnuocpanasonic
maybomnuocpanasonicmaybomnuocpanasonic
maybomnuocpanasonicBay Loan
 
Tratando seu blog como um (ótimo) negócio
Tratando seu blog como um (ótimo) negócioTratando seu blog como um (ótimo) negócio
Tratando seu blog como um (ótimo) negócioNick Ellis
 
AIESEC in Poland Expansion Process
AIESEC in Poland Expansion ProcessAIESEC in Poland Expansion Process
AIESEC in Poland Expansion Processaiesec_poland
 

Destaque (7)

Rồng Bay - Mai-Hương
Rồng Bay -  Mai-HươngRồng Bay -  Mai-Hương
Rồng Bay - Mai-Hương
 
Final magazine front cover
Final magazine front coverFinal magazine front cover
Final magazine front cover
 
If you can’t be found you won’t be found final
If you can’t be found you won’t be found finalIf you can’t be found you won’t be found final
If you can’t be found you won’t be found final
 
maybomnuocpanasonic
maybomnuocpanasonicmaybomnuocpanasonic
maybomnuocpanasonic
 
Tratando seu blog como um (ótimo) negócio
Tratando seu blog como um (ótimo) negócioTratando seu blog como um (ótimo) negócio
Tratando seu blog como um (ótimo) negócio
 
Icdl Clase2
Icdl Clase2Icdl Clase2
Icdl Clase2
 
AIESEC in Poland Expansion Process
AIESEC in Poland Expansion ProcessAIESEC in Poland Expansion Process
AIESEC in Poland Expansion Process
 

Semelhante a Enterprise flex pure mvc.v4

UAFPUG6 - PureMVC
UAFPUG6 - PureMVCUAFPUG6 - PureMVC
UAFPUG6 - PureMVCmandrew182
 
Шаблоны проектирования в Magento
Шаблоны проектирования в MagentoШаблоны проектирования в Magento
Шаблоны проектирования в MagentoPavel Usachev
 
Eleanor
EleanorEleanor
EleanorSC3402
 
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011camp_drupal_ua
 
Symfony2 practice
Symfony2 practiceSymfony2 practice
Symfony2 practiceSkorney
 
«трудности при разработке сложных распределённых систем на Java. способы реше...
«трудности при разработке сложных распределённых систем на Java. способы реше...«трудности при разработке сложных распределённых систем на Java. способы реше...
«трудности при разработке сложных распределённых систем на Java. способы реше...MDDay_4
 
Drupal организация разработки
Drupal   организация разработкиDrupal   организация разработки
Drupal организация разработкиAnna Fedoruk
 
Drupal -organizaciya_razrabotki
Drupal  -organizaciya_razrabotkiDrupal  -organizaciya_razrabotki
Drupal -organizaciya_razrabotkidrupalconf
 
ASP.NET, MVC, ASP.NET MVC
ASP.NET, MVC, ASP.NET MVCASP.NET, MVC, ASP.NET MVC
ASP.NET, MVC, ASP.NET MVCGetDev.NET
 
Аудит Active directory. Обзор программы NetWrix Active Directory Change Reporter
Аудит Active directory. Обзор программы NetWrix Active Directory Change ReporterАудит Active directory. Обзор программы NetWrix Active Directory Change Reporter
Аудит Active directory. Обзор программы NetWrix Active Directory Change ReporterNetwrix Россия/СНГ
 
Как пройти собеседование и получить первую работу на Swift
Как пройти собеседование и получить первую работу на SwiftКак пройти собеседование и получить первую работу на Swift
Как пройти собеседование и получить первую работу на SwiftAnton Loginov
 
Eleanor CMS
Eleanor CMSEleanor CMS
Eleanor CMSSC3402
 
Programming Guide
Programming GuideProgramming Guide
Programming Guideguest63e09c
 
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET» O...
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET»  O...ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET»  O...
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET» O...WDDay
 
Web deployment
Web deploymentWeb deployment
Web deploymentGetDev.NET
 

Semelhante a Enterprise flex pure mvc.v4 (20)

UAFPUG6 - PureMVC
UAFPUG6 - PureMVCUAFPUG6 - PureMVC
UAFPUG6 - PureMVC
 
PureMVC and Papervision
PureMVC and PapervisionPureMVC and Papervision
PureMVC and Papervision
 
MWWM
MWWMMWWM
MWWM
 
Шаблоны проектирования в Magento
Шаблоны проектирования в MagentoШаблоны проектирования в Magento
Шаблоны проектирования в Magento
 
Views обзор
Views обзорViews обзор
Views обзор
 
Eleanor
EleanorEleanor
Eleanor
 
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011
Yury Glushkov.What should we build a website.Drupal Camp Kyiv 2011
 
Symfony2 practice
Symfony2 practiceSymfony2 practice
Symfony2 practice
 
«трудности при разработке сложных распределённых систем на Java. способы реше...
«трудности при разработке сложных распределённых систем на Java. способы реше...«трудности при разработке сложных распределённых систем на Java. способы реше...
«трудности при разработке сложных распределённых систем на Java. способы реше...
 
Drupal организация разработки
Drupal   организация разработкиDrupal   организация разработки
Drupal организация разработки
 
Drupal -organizaciya_razrabotki
Drupal  -organizaciya_razrabotkiDrupal  -organizaciya_razrabotki
Drupal -organizaciya_razrabotki
 
ASP.NET, MVC, ASP.NET MVC
ASP.NET, MVC, ASP.NET MVCASP.NET, MVC, ASP.NET MVC
ASP.NET, MVC, ASP.NET MVC
 
Backbone lesson 1
Backbone lesson 1Backbone lesson 1
Backbone lesson 1
 
Аудит Active directory. Обзор программы NetWrix Active Directory Change Reporter
Аудит Active directory. Обзор программы NetWrix Active Directory Change ReporterАудит Active directory. Обзор программы NetWrix Active Directory Change Reporter
Аудит Active directory. Обзор программы NetWrix Active Directory Change Reporter
 
Как пройти собеседование и получить первую работу на Swift
Как пройти собеседование и получить первую работу на SwiftКак пройти собеседование и получить первую работу на Swift
Как пройти собеседование и получить первую работу на Swift
 
Eleanor CMS
Eleanor CMSEleanor CMS
Eleanor CMS
 
Programming Guide
Programming GuideProgramming Guide
Programming Guide
 
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET» O...
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET»  O...ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET»  O...
ВІТАЛІЙ ГОНЧАРУК «За допомогою чого пишуться серйозні веб додатки на .NET» O...
 
Сервлеты
СервлетыСервлеты
Сервлеты
 
Web deployment
Web deploymentWeb deployment
Web deployment
 

Enterprise flex pure mvc.v4

  • 1. FlexPure MVC архитектура для приложений enterprise уровня Описание: 1. Сначала мы вспомним основные составляющие микроахитектурыPureMVC, используя презентацию SamuelAsherRivello. 2. Далее рассмотрим структуру и задачи, возникающие при использовании PureMVC в больших проектах. a. Разновидности и жизненный цикл элементов системы b. Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми элементами. 3. «Страничная» архитектура для PureMVC проекта: a. Управление View компонентами в «страничной» архитектуре: i. отложенное (deferred) создание, ii. расположение в иерархии DisplayObjects- слоты, медиаторы-слотхолдеры и их взаимодействие с медиаторами-клиентами. b. Жизненный цикл «страницы», дескриптор «страницы» c. Прелоадер страницы 4. Взаимодействие View Components и Mediators a. Шаблон «страницы» b. Интерфейс «страничного» View Component c. Обмен данными между медиатором и View компонентом. d. Состояние «редактирования» (Editing state) e. Обработка нажатий кнопок (Buttons) f. Обработка других команд (пример – Chevrons) 5. Использование модулей в «страничной» архитектуре. Требования к слушателям: знание AS3, жизненного цикла компонентов Flex, PureMVChttp://puremvc.org Докладчик: Сергей Шичинов - SergiyShychynov (EPAM)Sergiy_Shychynov@epam.com Примечание: пункт 4 был исключён из доклада для того чтобы длительность доклада соответствовала регламенту. 2012-03-24
  • 2. Основные составляющие PureMVC (используя презентацию SamuelAsherRivello) http://www.adobe.com/newsletters/inspire/december2008/articles/article6/index.html MVC in PureMVC Схема взаимодействия компонентов PureMVC для выполнения элементарной операции: - Внешний вид компонента HelloGoogle – кнопка и текстовое поле для сообщения - Последовательность элементарных действий выполняемых при нажатии кнопки - Положение этих действий на диаграмме PureMVC
  • 3.
  • 4. Основные задачи, возникающие при использовании PureMVC в больших проектах. Когда речь идет о приложение enterprise уровня, то это означает что они БОЛЬШИЕ. То есть имеется БОЛЬШОЕ количество РАЗНЫХ форм и компонентов, которые необходимо будет использовать в разных ситуациях и в разное время. И речи о том, что все элементы будут созданы одновременно или заранее быть не может. Более того – было бы неплохо, чтобы и грузить их все сразу не требовалось. Рассмотрим несколько разных «видов» гипотетического большого приложения.
  • 5.
  • 6. Среди всего UIбольшого приложения можно выделить элементы (подсистемы): 1. Которые постоянно находятся на экране и доступны для взаимодействия. 2. Которые могут вызываться пользователем на экран по желанию и ведут себя относительно независимо от других элементов UI. 3. Которые имеют отношение к текущей операции, выполняемой пользователем, показываются на экране когда он начинает выполнять эту операцию и будут убраны с экрана когда он эту операцию завершит.Причем таких циклов появления и исчезновения с экрана может быть много. Этот третий тип подсистем мы будем в дальнейшем называть страницами – Pages.
  • 7. И если операции по обслуживанию жизненного цикла (описанные далее) для компонетов 1 и 2 типа можно выполнить один раз (например в StartupCommand), то выполнение всех нижеперечисленных действий для компонентов подсистем 3-его типа является рутинной операцией и нуждается в автоматизации. Жизненный цикл элементов системы Каждая подсистема 3 типа («страница») может состоять из одного или нескольких видимых элементов, функционирующих совместно в одном промежутке времени. И для функционирования любой отдельной подсистемы нашей большой системы нам будет необходимо: 1. Создать (инстанциировать) и разместить на экране (в иерархии DisplayObjects) необходимые компоненты - ViewComponents. (Здесь и дальше компонентом будет называться видимый элемент, занимающий место в иерархии DisplayObjects.) 2. создать и зарегистрировать необходимые медиаторы – Mediators. 3. связать медиаторы с соответствующими компонентами a. медиаторы должны иметь ссылки на свои компоненты, для того чтобы передавать в них данные и совершать действия b. медиаторы прослушивают события – Events от компонентов для того чтобы узнать что нужно что- то делать 4. зарегистрировать необходимые для работы подсистемы комманды – Commands (связать их с Notifications), 5. создать и зарегистрировать необходимые для работы прокси–Proxy, 6. отобразить в наших компонентах валидные данные и обеспечить взаимодействие a. Как правило, эти данные загружаются извне (с сервера). Это может занять определенное время. Эти данные возможно не получится загрузить в результате ошибки. И возможно имеются некие политики безопасности, которые в зависимости от того какие именно данные хочет увидеть пользователь, могут не разрешить ему увидеть эти данные – и мы не узнаем о том разрешено это или нет, пока не получим ответ с сервера. Во всех этих случаях неразумно показывать на экране новые компоненты, еще не заполненные данными, до того как эти данные будут получены с сервера. Это процесс мы будем называть предзагрузка – preloader. b. Во время работы пользователя с подсистемой, коммуникация с сервером обеспечивается по стандартной схеме изложенной выше.
  • 8. c. Отдельный вопрос – это обработка ошибок (серверных) – в зависимости от типа ошибок мы может либо дальше продолжать оставаться на странице, либо потребуется обновить ее, либо придется покинуть ее. 7. После того как пользователь завершил операцию нам необходимо корректно освободить ресурсы системы от текущей «страницы» (очевидно перед тем как будет открыта следующая). a. Удаление «актеров» PureMVC (медиаторов) i. «отписать» медиаторы от системы (unregister) чтобы они не прослушивали больше нотификейшены. ii. Можно также удалять медиаторы, но можно сохранять их в «кэше» до следующего использования. iii. Команды тоже можно «отписать» от системы, но это не обязательно. iv. Некоторые прокси можно было бы тоже отписывать от системы и удалять, но обычно этого не нужно. И даже вредно. b. Отписывание медиаторов от events, которые они прослушивали от компонентов. c. Удаление видимых компонентов. Вообще говоря, операция создания компонента и добавления его в DisplayList гораздо более ресурсоемкая, чем сделать невидимый компонент – видимым. Поэтому для увеличения перформанса и для того чтобы видимые элементы появлялись более плавно вместо удаления компонентов лучше делать их невидимыми. d. Если в процессе выполнения операций были загружены какие-то большие данные и ссылки на них сохранились в компонентах или «актерах» PureMVC – то нужно их очистить, чтобы позволить GarbageCollector –у освободить память. Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми элементами. Как известно видимые элементы – компоненты флекса не создаются мгновенно по запросу. Как правил от момента создание экземпляра компонента, установки его свойств и добавления его в иерархию DisplayObjectsпроходит некоторое время и несколько этапов, прежде чем событие «creationComplete»дает нам знать, что компонент и все его подкомпоненты полностью созданы и готовы к работе. До этого момента медиатор, даже если и будет иметь ссылку на компонент, не сможет полноценно с ним работать. DefferedMediator Решает проблему асинхронного создания компонентов. Откладывает вызовы initialize и activate до момента, когда компонент будет создан и инициализирован. А потом еще откладывает update до момента, когда все медиаторы из списка будут активированы. Constructor() – чистый конструктор (не выполняющий никаких действий) * Override it to complete setup mediator properties and associate mediator * with the View Component. Use setupMediator function to do most of the tasks. function create():void * The method is called after component <code>creationComplete</code> event. * Create it to add listeners and make additional view component initialization. function initialize():void; * This method is called every time when you show and activate the view component. * Override it to add additional mediator's and view component's activation. functionactivate():void; waitForMediatorsActivation(mediatorNames); * Override it to update view component in accordance with current viewParams. * You can process here both stateParams and viewParams. * Is called after initialize() (after creationComplete event) and
  • 9. * activate() methods. function update():void * Deactivate mediator (remove from pureMVC workflow). * You can override it to make additional deactivation. functiondeactivate():void; * Create it to remove listeners and make additional view component finalization. functionfinalize():void; Кто, когда и как создает видимые элементы. Слоты, медиаторы-слотхолдеры и их взаимодействие с компонентами-клиентами. Задача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор. Медиатору известен класс его компонента. При создании медиатора – в методе create() – медиатор создает экемпляр вью компонента и помещает его в DisplayList. Делается это с помощью концепции медиаторов- слотхолдеров, которые имеют в составе своего компонента slot – контейнер (обычно ViewStack) в который можно поместить, найти и удалить комопнент. SlotViewComponentDescription viewComponentName:String, viewComponentSlot:String, viewComponent:UIComponent SlotAMediator M1Mediator медиатор-слотхолдер медиатор-клиент SlotAMediator получает M1Mediator создает нотификейшен, адресованный ему компонет и отправляет его и добавляет в свой слот (ViewStack слоту "SlotAMediator" - или другой контейнер) новый просит его хранить под компонет под именем "M1" именем "M1"
  • 10.
  • 11. «Страничная» архитектура для PureMVC проекта Мы ввели понятие страниц – Pages. «Страница»– это некоторое множество видимых элементов, функционирующих совместно в одном промежутке времени. Эти компоненты и обслуживающие их актеры PureMVC совместно создаются, работают и удаляются. Выполнением всех этих операций в PureMVC традиционно занимаются команды. Чтобы не писать отдельные команды для открытия каждой страницы, была создана единая команда открытия новой страницы ViewPageCommand. Эта команда выполняет все необходимые при открытии страницы действия в соответствии с переданным ей в качестве входного параметра дескриптором страницы. Она работает совместно с PagesProxy, которыйи является хранителем информации обо всех доступных в системе «страницах» и «состояния» текущей открытой страницы. Основные задачиPagesProxy: - хранение справочника всех страницах в системе functiongetPageDescription(pageName:String):PageDescription - хранение информации о текущей открытой странице (ее имя, дескриптор, стейт, состояние редактирование, helpContext и прочее) Соответственно все страницы имеют уникальное имя publicclass Pages { publicstaticconstABOUT:String = "about"; publicstaticconstADMIN_EMAIL_TEMPLATE_EDIT:String = "adminEmailTemplateEdit"; publicstaticconstDOCUMENT_TRANSLATION:String = "documentTranslation"; … } идескрипторы PageDescription pageName:String, preloader:Class, - наследникBasePagePreloader mediators:Array, - списокклассовнаследониковBaseMediator proxies:Array = null, commands:Array = null, - списокCommandDescription(name:String, commandClass:Class) stateParams:Object = null, - редко встречающиеся дополнительные параметры pageTitle:String = null, } - часто встречающиеся дополнительные параметры breadcrumbs:Array = null. … } Примердескриптора страницы: newPageDescription(Pages.QUESTIONNAIRE, QuestionnaireAnswerPreloader, [QuestionnaireSlotHolderMediator, QuestionnaireAnswerMediator], [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy, TimeScaleProxy], [ newCommandDescription(SPNotification.FIND_NEW_QUEST, LoadQuestiannairCommand), newCommandDescription(SPNotification.UPDATE_ASSET_QUEST, UpdateAssetForQuestCommand), ], {questionnaireComponentState: QuestionnaireComponentState.ANSWER}, "Questionnaire Registry" ) PageNotificationParams varpageName:String;
  • 12. varpageState:String; varid:Number; varbackPageName:String; varpreloader:BasePreloaderMediator; - создается и добавляется в процессе открытия страницы ViewPageCommand 1. Проверяет наличие дескриптора страницы и при необходимости подгружает модуль содержащий страницу. Входными параметрами для открытия страницы являются: a. pageDescriptor – находится по имени страницы b. stateParams : {} – является дополнительным набором параметров страницы (которые не вошли в сам дескрипотор – так как редко используются) c. viewParams: PageNotificationParams – дополнительные параметры страницы, заполняемые при ее открытии 2. Создает и регистрирует необходимые прокси (они могут быть нужны прелоадеру) 3. Создает и запускает прелоадер a. load() b. validate() + препроцессинг 4. Если прелоадер «дал добро», то закрывает текущую страницу a. отписывает от системы медиаторы b. подчищает «временные» данные (на вью компонентах и медиаторах!) c. отписывает медиатор от events компонентов d. добавляет ссылку на прелоадер с загруженными и подготовленными данными во viewParams 5. Регистрирует команды 6. Создает (или достает из кеша) медиаторы, передает им значения stateParams и viewParams и регистрирует их в системе. a. Если медиаторы создаются то это делается в следующем порядке i. Конструктор ii. Setup params (stateParamsиviewParams) iii. create() b. если достается из кеша, то просто Setupparams (stateParams и viewParams) 7. Активирует медиаторы. В процессе активации медиаторы должны создать свои компоненты, разместить их в иерархии DisplayLists, сделать видимыми и подписаться на необходимые events. 8. После активации всех медиаторов вызывается update() Прелоадер – Preloader Прелоадерслужитдлятогочтобызагрузитьнесколько «частей» данных (используяпроксиилинепосредственноделегаты). После полной загрузки всех частей возможна их валидация и дополнительная обработка. Прелоадер отрабатывает при попытке открыть новую «страницу» до того как она будет реально открыта. В случае если валидатор прелоадера выдает false, страница не будет открыта. Вместо этого будет выведено сообщение об ошибке. Фрагмент кода вызова прелоадера при открытии страницы if(pageDesc.preloader != null) { setLoadingState(true); registerProxies(); // for preloadin purposes varpreloaderMediator:BasePreloaderMediator = new (pageDesc.preloader)(); preloaderMediator.viewParams = params; preloaderMediator.stateParams = pageDescriptor.stateParam; preloaderMediator.callback = executeAfterPreload; preloaderMediator.load(); BasePreloaderMediator varstateParams:Object; varviewParams:PageNotificationParams;
  • 13. * Override it to create more preloader parts. You can use viewParams and stateParams. function load():void { //... addDelegatePreloaderPart("YYYid", ResourceTypeDelegate.instance.getResourceTypeById(id)); //... addNotificationPreloaderPart("XXXid", XXXResultNotification, XXXFaultNotification); xxxProxy.load(blablabla); //... activate(); } * Override it to validate loaded data. If ERROR - you have to setup * preloader.errorKey before returning false value. function validate():Boolean { if(preloader.errorKey == null) { // достаем нужное нам данное и проверяем getPart("YYYid") – используем для проверки } return (preloader.errorKey == null); } Пример прелоадера «детям до 16» publicclassManageGroupMembershipPreloaderextendsBasePreloaderMediator { overridepublicfunction load():void { varid:Number = getID(true); if(!isNaN(id)) addDelegatePreloaderPart(ContactProxy.CONTACT, ContactDelegate.instance.getContactById(id) ); addNotificationPreloaderPart(LanguageProxy.PLAIN_LANGUAGE_LIST, SPNotification.PLAIN_LANGUAGE_LIST_LOADED, SPNotification.PLAIN_LANGUAGE_LIST_FAILED); LanguageProxy(facade.retrieveProxy(LanguageProxy.NAME)).getPlainLanguageList(); super.load(); } overridepublicfunction validate():Boolean { if(super.validate()) { varcontact:Contact = getPart(ContactProxy.CONTACT) as Contact; if(contact != null&&contact.age< 16) setPreloaderError("Просмотр этой страницы не разрешен детям до 16"); returnsuper.validate(); } } Модульность В настоящее время система имеет:  полторы сотни (150) основных страниц со связанными с ними rollover формами,  несколько десятков popup-форм  некоторое кол-во подсистем,  работающих постоянно на экране,  вызываемых по требованию пользователя
  • 14. или работающий в качестве «демонов» – daemon (ping, systemmessages)  и«сервисов» (messages, multiple operations, progress indication etc.) Кодовая база клиентской части проекта включает более 2000 файлов. Из них более 1600 as файлов и около 400 mxml. При этом с точки зрения заказчика это все разбито на 8 логических «модулей» и лицензия на использование каждого из них может покупаться отдельно. Кроме того многие пользователи могут не иметь доступа к некоторым модулям (администрирование, отчеты) по соображениям секьюрности или в соответствии с их ролями. Понятно, что вопрос о том чтобы не грузить все это сразу при открытии приложения возник уже давно.То есть необходимо при запуске загрузить только ядро приложения а решение о необходимости подгрузки дополнительного функционала уже принимать по ситуации. Необходимо: при начальной загрузке загружать только ядро системы, а все дополнительные, не всегда или редко используемые возможности подгружать по требованию. Для уменьшения времени загрузки и потребляемого трафика. RSLдля этого использовать нельзя, так как для RSLприходилось бы вручную выбирать какие классы включать в эту библиотеку а какие - нет. Что неприемлемо при колве классов больше 2000. Флексовые модули для этого как бы не задумывались (это скорее неудачный способ монетизации флексовых приложений), но воспользоваться ими получилось. - Флексовый линкер при компиляции модуля позволяет собрать все классы, по цепочке зависимостей - есть возможность указать линкеру, что необходимо исключить классы, которые уже есть в ядре приложения. И в разбиении системы на модули очень помогло то, что мы имели большинство функционала, организованного в виде «страниц». Страницы были использованы как ноды для дерева линковки всех классов, необходимых для работы текущего модуля. Таким образом, модуль подгружает ViewPageCommandв момент когда впервые понадобиться страница содержащаяся в этом модуле. После загрузки модуля (и всех его классов) все PageDescriptors, содержавшиеся в этом модуле добаляются в список доступных страниц в PagesProxy. Структура иерархии модулей Module – единица компиляции и линковки ModuleDescription – содержитполныйнаборвсехPageDescriptorsмодуля PageDescriptionsXXX – логически сгруппированные наборы дескрипторов страниц moduleDescriptors.xml – справочник, содержащий информацию о том какая страница в каком модуле содержится flex-include-vo.xml – список всех VO системы для включения в ядро системы (решение проблемы регистрации VO для ремотинга) Соответствующие ANTскрипты. !!!НИКОГДА не включайте модули из среды FlashBuilder!!! Проблема регистрации классов для римотинга. [RemoteClass(alias="com.os.sp.domain.messaging.MessagesGroup")] publicclassMessagesGroupextendsMessagesGroupBaseimplementsIOSSPMessage{} Не регистрирует класс, если VOлинкуется через модуль! Решение проблемы: 1) вмодуледелаемregisterServerClass(MessagesGroup); publicstaticfunctionregisterServerClass(classRef:Class):void { registerClassAlias(getClassServerName(classRef), classRef);
  • 15. } 2) линкуем все VOв ядро системы (flex-include-vo.xml <?xmlversion="1.0"?> <flex-config> <includesappend="true"> <symbol>com.os.sp.domain.administration.authorization.ContactGroupIPRange</symbol> <symbol>com.os.sp.domain.messaging.MessagesGroup</symbol> <symbol>com.os.sp.domain.messaging.SmsCostConfig</symbol> <symbol>com.os.sp.domain.integrity.InvalidRecord</symbol> <symbol>com.os.sp.domain.reporting.monitoring.GenerationState</symbol> </includes> </flex-config> publicfunctionModuleMain() { super(); _moduleDescription = newModuleDescriptionMain(); //NameUtils.registerServerClass(ContactTask); //NameUtils.registerServerClass(ReportResponse); initializeModule(); } publicfunctionModuleDescriptionMain() { super("ModuleMain", [], [] .concat(PageDescriptionsMain.pageDescriptions) .concat(PageDescriptionsMyShadowPlanner.pageDescriptions) .concat(PageDescriptionsContacts.pageDescriptions) .concat(PageDescriptionsResourcesAssets.pageDescriptions) .concat(PageDescriptionsReporting.pageDescriptions) ); } publicclassPageDescriptionsResourcesAssets { publicstaticconstcommonBreadcrumbs:Array = [Pages.R_A_VIEW_ROOT_RESOURCES]; publicstaticconstcommonProxies:Array = [ResourceTypeProxy, ParentListProxy, SessionDataProxy,AssetProxy, ProcessEditProxy, ProcessesListProxy]; publicstaticconstpageDescriptions:Array = [///////////////////////////////////////////// newPageDescription(Pages.UPDATE_RESOURCE_TYPE, PageState.ADD_EDIT_VIEW, ResourceTypeEditPreloader, Pages.R_A_VIEW_ROOT_RESOURCES, [ResourcesSlotHolderMediator, ResourceTypeEditMediator], [SessionDataProxy, AssetProxy, ProcessEditProxy], [ newCommandDescription(SPNotification.FIND_ASSET_FOR_DETAILS, LoadAssetCommand), newCommandDescription(SPNotification.FIND_ASSET_FOR_EDIT, LoadAssetEditCommand), ], {accessArea: AccessArea.RESOURCE_TYPES}, commonBreadcrumbs.concat(), "page.updateResourceType.title",
  • 16. "page.updateResourceType.breadcrumbLabel", null ).addAddPageState(null, "page.createResourceType.title", "page.createResourceType.breadcrumbLabel" ).addViewPageState(null, "page.updateResourceType.viewTitle", "page.updateResourceType.viewBreadcrumbLabel" ).addLibraryPageState( Pages.R_A_UPDATE_RESOURCE_TYPE_FOR_LIBRARY ), newPageDescription( Pages.QUESTIONNAIRE, PageState.EDIT_VIEW, QuestionnaireAnswerPreloader, null, [QuestionnaireAnswerMediator], [QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy], null, {questionnaireComponentState:QuestionnaireComponentState.ANSWER}, [TreeNodeBase.NODE_BIA] ).registerRollover(Rollovers.QUESTIANNAIRE_RECOVERY_SCHEDULE, PageState.ADD_EDIT_VIEW ).registerRollover(Rollovers.QUESTIONNAIRE_ADD_PROCESS, PageState.ADD_EDIT_VIEW ) ] ///////////////////////////////////////////// } moduleDescriptors.xml <?xmlversion="1.0"encoding="UTF-8"?> <Modules> <Modulename="ModuleMain"> <Pages> <Pagename="about"/> <Pagename="myTasksPage"/> <Pagename="myResponsibilitiesPage"/> <Pagename="myPasswordPage"/> </Pages> <Dependencies/> </Module> <Modulename="ModuleAdministration"> <Pages> <Pagename="adminLogo"/> <Pagename="adminLanguageEditor"/> <Pagename="auditTrail"/> </Pages> <Dependencies/> </Module> <Modulename="ModuleQuestionnaires"> <Pages> <Pagename="questionnaires"/> <Pagename="questionnaire"/> <Pagename="questionnaireTemplates"/> </Pages> <Dependencies/> </Module> </Modules> Фрагмент ant-task-а компиляции основного приложения (ядра системы) <property name="FLEX_INCLUDE_VO_CONFIGURATION" value="${MAIN_SOURCE_FOLDER}/flex-include-vo.xml" /> <mxmlc file="${MAIN_SOURCE_FOLDER}/${ROOT_APPLICATION}.mxml" output="@{output}.swf" link-report="${BUILD_FOLDER}/${ROOT_APPLICATION}.${FULL_LINK_REPORT_POSTFIX}"
  • 17. > <load-configfilename="${FLEX_LOCAL_CONFIGURATION}"/> </mxmlc> Компиляциямодулей <targetname="compile-modules"if="flex.modular.exist"> <compile-module-simplemoduleName="ModuleAdministration"/> <compile-module-simplemoduleName="ModuleMessaging"/> <compile-module-simplemoduleName="ModuleImportExport"/> </target> Фрагмент из макроопределения компиляции модуля <mxmlcfile="${MODULE_SOURCE_FOLDER}/@{moduleName}.@{moduleType}" output="${BUILD_FOLDER}/@{moduleName}.swf" load-externs="${BUILD_FOLDER}/@{dependsOn}.${FULL_LINK_REPORT_POSTFIX}" > </mxmlc> Приложение: особенности реализации SlotHolderмедиаторов Задача по созданию и связыванию вью компонентов с медиаторами возложена на медиатор. Медиатору известен класс его компонента. При создании медиатора – в методе create() – медиатор создает инстанс класса вью компонента и отправляет его слот-холдермедиатору чтобы тот поместил его себе в DisplayList. protectedfunctionsetupMediator(…) mediatorName:String = null, // AUTO – такое же как имя класса – для регистрации в PureMVC viewComponentReference:Object = null, // 1) null must be null, // 2) component class // 3) component instance (descendant of UIComponent) viewComponentName:String = null, // viewComponent custom name // AUTO – по имени медиатора без постфикса Mediator // будет использовано как id и name в слотхолдере viewComponentSlot:String = null, // specific slot for register/find viewComponent (if need) viewComponentInitAction:int = 0 // special init action (0 - no action) INIT_NONE:int = 0; // no action INIT_FIND_OR_WAITING_FOR_THE_VIEW_COMPONENT:int = 1; // find view component with appropriate name in appropriate slot or (in not found) // listen for the BaseNotifications.SLOT_VIEW_COMPONENT_CREATION_COMPLETE notification INIT_FIND_VIEW_COMPONENT:int = 2; // find view component with appropriate name in appropriate slot INIT_ADD_TO_SLOT:int = 4; // add view component to appropriate slot using appropriate name overridepublicfunctionlistNotificationInterests():Array { return (slots == null) ? super.listNotificationInterests() : super.listNotificationInterests().concat( BaseNotifications.SLOT_VIEW_COMPONENT_ADD, BaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME,
  • 18. BaseNotifications.SLOT_VIEW_COMPONENT_SHOW, BaseNotifications.SLOT_VIEW_COMPONENT_HIDE, BaseNotifications.SLOT_VIEW_COMPONENT_FIND ); } overridepublicfunctionhandleNotification(notification:INotification):void { super.handleNotification(notification); … } privatefunction defaultSlotHolderNotificationHandler(notification:INotification):void { if(slots && slots[notification.getType()]) { vardesc:SlotViewComponentDescription = notification.getBody() as SVCD; varcomponent:UIComponent; component = getViewComponentFromSlot(desc.viewComponentSlot, desc.viewComponentName); switch(notification.getName()) { caseBaseNotifications.SLOT_VIEW_COMPONENT_SHOW: FlexUIComponentsUtils.showViewComponent(component, true); break; caseBaseNotifications.SLOT_VIEW_COMPONENT_HIDE: component.visible = false; break; caseBaseNotifications.SLOT_VIEW_COMPONENT_ADD: addViewComponentToInternalSlot(desc); desc.viewComponent = null; // mark viewComponent as added break; caseBaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME: removeViewComponentFromSlotByName(desc); break; caseBaseNotifications.SLOT_VIEW_COMPONENT_FIND: desc.viewComponent = component; break; }}} Далее описанантипаттерн, который используется для оптимизации взаимодействия слотхолдеров. Но мне не стыдно, потому что это, с одной стороны – служит оптимизации (можно было и не делать), с другой – можно было бы без этого обойтись просто воспользовавшись синглтоном-менеджером. * Register handler for Notification - works just like addEventListebner. * It doesn't depend on registerMediator/removeMediator !BE AWARE! functionaddNotificationListener(notificationName:String, handler:Function):void { org.puremvc.as3.core.View.getInstance().registerObserver( notificationName, new Observer(handler, this) ); } * Remove Notification handler - works just like removeEventListebner. * It doesn't depend on registerMediator/removeMediator !BE AWARE! functionremoveNotificationListener(notificationName:String):void { org.puremvc.as3.core.View.getInstance().removeObserver( notificationName, this ); } Примериспользования: * Try to add view component in appropriate external slot. If there isn't * appropriate slot then start waiting for SLOT_CREATION_COMPLETE. functionaddViewComponentToExternalSlot():void { vardesc:SlotViewComponentDescription = newSlotViewComponentDescription
  • 19. viewComponentName, viewComponentSlot, viewComponentasUIComponent ); varaddNotification:INotification = new Notification( BaseNotifications.SLOT_VIEW_COMPONENT_ADD, desc, viewComponentSlot); facade.notifyObservers(addNotification); if(desc.viewComponent != null) // егобыобнулилиеслибыонбылнайден { addNotificationListener(BaseNotifications.SLOT_CREATION_COMPLETE, handleSlotCreationCompleteNotificationToAddViewComponent); } }