Enterprise flex pure mvc.v4
Upcoming SlideShare
Loading in...5
×
 

Enterprise flex pure mvc.v4

on

  • 524 views

Flex Pure MVC архитектура для приложений enterprise уровня. Черновик доклада для UA FPUG - встреча 35.

Flex Pure MVC архитектура для приложений enterprise уровня. Черновик доклада для UA FPUG - встреча 35.

Statistics

Views

Total Views
524
Slideshare-icon Views on SlideShare
524
Embed Views
0

Actions

Likes
0
Downloads
2
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft Word

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Enterprise flex pure mvc.v4 Enterprise flex pure mvc.v4 Document Transcript

    • 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.htmlMVC 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 mediators and view components 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) в которыйможно поместить, найти и удалить комопнент.SlotViewComponentDescriptionviewComponentName: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";…}идескрипторыPageDescriptionpageName:String,preloader:Class, - наследникBasePagePreloadermediators:Array, - списокклассовнаследониковBaseMediatorproxies: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")PageNotificationParamsvarpageName: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 purposesvarpreloaderMediator:BasePreloaderMediator = new (pageDesc.preloader)();preloaderMediator.viewParams = params;preloaderMediator.stateParams = pageDescriptor.stateParam;preloaderMediator.callback = executeAfterPreload;preloaderMediator.load();BasePreloaderMediatorvarstateParams: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 – такое же как имя класса – для регистрации в PureMVCviewComponentReference: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 nameoverridepublicfunctionlistNotificationInterests():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 addedbreak;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 doesnt 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 doesnt 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 isnt* 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); }}