50
Flex Pure MVC архитектура для приложений enterprise уровня Sergiy Shychynov (EPAM) 2012-03-24

Enterprise flex pure mvc, slides, russian

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: Enterprise flex pure mvc, slides, russian

Flex Pure MVC архитектура для приложений enterprise уровня

Sergiy Shychynov (EPAM) 2012-03-24

Page 2: Enterprise flex pure mvc, slides, russian

Содержание1. Сначала мы вспомним основные составляющие

микроахитектуры PureMVC.2. Далее рассмотрим структуру и задачи, возникающие

при использовании PureMVC в больших проектах.1. Разновидности и жизненный цикл элементов системы2. Необходимость синхронизации работы медиаторов с

асинхронно создаваемыми видимыми элементами.

3. «Страничная» архитектура для PureMVC проекта:1. Управление View компонентами в «страничной» архитектуре:

1. Отложенное (deferred) создание, 2. Расположение в иерархии Display Objects.

2. Жизненный цикл «страницы», дескриптор «страницы»3. Прелоадер страницы

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

Page 3: Enterprise flex pure mvc, slides, russian

Основные составляющие PureMVC

используя презентацию Samuel Asher Rivello)http://www.adobe.com/newsletters/inspire/december2008/articles/article6/index.html

MVC in PureMVC

Page 4: Enterprise flex pure mvc, slides, russian
Page 5: Enterprise flex pure mvc, slides, russian

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

– кнопка и текстовое поле для сообщения

Последовательность элементарных действий выполняемых при нажатии кнопки

Положение этих действий на диаграмме PureMVC

Page 6: Enterprise flex pure mvc, slides, russian
Page 7: Enterprise flex pure mvc, slides, russian

Основные задачи, возникающие при использовании PureMVC в больших проектах.

«Приложение enterprise уровня» - БОЛЬШИЕ

БОЛЬШОЕ количество РАЗНЫХ форм и компонентов, которые необходимо будет использовать в разных ситуациях и в разное время

Речи о том, что все элементы будут созданы одновременно или заранее быть не может. Более того – было бы неплохо, чтобы и грузить их все сразу не требовалось.

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

Page 8: Enterprise flex pure mvc, slides, russian

Форма - Списки контактов и контактных групп

Page 9: Enterprise flex pure mvc, slides, russian

Форма – менеджер валют

Page 10: Enterprise flex pure mvc, slides, russian

Форма – редактирование контакта

Page 11: Enterprise flex pure mvc, slides, russian

Форма - Аудит

Page 12: Enterprise flex pure mvc, slides, russian

Форма – Редактирование конвейера операций маппинг процессора для бла-бла-бла

Page 13: Enterprise flex pure mvc, slides, russian

Форма – Маппинг полей метода сервиса передачи телефонных сообщений.

Page 14: Enterprise flex pure mvc, slides, russian

3 вида компонентов

Page 15: Enterprise flex pure mvc, slides, russian

Среди всего UI большого приложения можно выделить элементы (подсистемы)1. постоянно находятся на экране и доступны для

взаимодействия.

2. могут вызываться пользователем на экран по желанию и ведут себя относительно независимо от других элементов UI.

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

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

Page 16: Enterprise flex pure mvc, slides, russian

Жизненный цикл элементов системы и основные операции над ними.1. создать и разместить в иерархии DisplayObjects необходимые компоненты -

ViewComponents.2. создать и зарегистрировать необходимые медиаторы – Mediators.3. связать медиаторы с соответствующими компонентами

ссылки на компоненты, прослушивание события от компонентов

4. зарегистрировать необходимые для работы подсистемы команды – Commands 5. создать и зарегистрировать необходимые для работы прокси – Proxy,6. отобразить в компонентах валидные данные

1. загружаются с сервера - определенное время2. загружаются с сервера – «ошибки технические»3. политики безопасности – запрещено смотреть данные – «ошибки логические»4. Не стоит показывать на экране новые компоненты, еще не заполненные данными, до того как эти

данные будут получены с сервера. 5. Это процесс мы будем называть предзагрузка – preloader.

7. основной цикл работы – стандартный1. Отдельный вопрос – это обработка ошибок (серверных). Бывают устранимые и неустранимые

ошибки – остаемся на странице, обновляем или покидаем ее.

8. после завершения операции - корректно освободить ресурсы системы от текущей «страницы»

1. Отписывание медиаторов от событий, которые они прослушивали от компонентов.2. Удаление «актеров» PureMVC (медиаторов)

1. «отписать» медиаторы от системы (unregister)2. удалять медиаторы или сохранять их в «кэше» 3. команды тоже можно «отписать» от системы,4. прокси отписывать от системы и удалять – как правило не нужно и даже вредно.

3. Удаление видимых компонентов - операция создания компонента и добавления его в DisplayList более ресурсоемкая, чем сделать невидимый компонент – видимым. НЕ удалять а делать невидимыми

4. Очистить ссылки на временные данные - Garbage Collector освободит память.

Page 17: Enterprise flex pure mvc, slides, russian

Необходимость синхронизации работы медиаторов с асинхронно создаваемыми видимыми элементами.

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

До этого момента медиатор, даже если и будет иметь ссылку на компонент, не сможет полноценно с ним работать.

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

Page 18: Enterprise flex pure mvc, slides, russian

DefferedMediator constructor() – чистый конструктор

create(); - все что хотелось сделать в конструкторе

initialize(); - в том числе addViewListeners уровня инициализации

activate();  - в том числе addViewListeners уровня активации

waitForMediatorsActivation(mediatorNames);  update(); - основной цикл

  deactivate(); – в том числе автоматически удаляет eventListeners уровня

активации

finalize(); – в том числе автоматически удаляет eventListeners уровня инициализации

Page 19: Enterprise flex pure mvc, slides, russian

Кто, когда и как создает видимые элементы.Медиатор знает класс своего(-их) компонентов.

Медиатор знает где должен быть его компонент.

Медиатор-клиент M1Mediator создает компонент и отправляет его слоту "SlotAMediator" - просит его хранить под именем "M1“. Обычно в методе create()

Медиатор-слотхолдер “SlotAMediator” получает нотификейшен, адресованный ему и добавляет в свой слот новый компонент под именем "M1“.

Слот – это обычно ViewStack или другой контейнер.

SlotViewComponentDescription viewComponentName = "M1“ viewComponentSlot = "SlotAMediator" viewComponent = UIComponent

Page 20: Enterprise flex pure mvc, slides, russian

Пример взаимодействия слот-холдера и его клиентов

Page 21: Enterprise flex pure mvc, slides, russian
Page 22: Enterprise flex pure mvc, slides, russian
Page 23: Enterprise flex pure mvc, slides, russian
Page 24: Enterprise flex pure mvc, slides, russian

«Страничная» PureMVC архитектура«Страница» – это некоторое множество компонентов, функционирующих совместно в одном промежутке времени.

Эти компоненты и обслуживающие их актеры PureMVC совместно создаются, работают и удаляются.

Чтобы не писать отдельные команды для открытия каждой страницы, была создана единая команда открытия новой страницы ViewPageCommand, которая использует PageDescription страницы и работает совместно с Pages Proxy.

Page 25: Enterprise flex pure mvc, slides, russian

Основные задачи PagesProxy

хранение справочника всех страниц системы function getPageDescription(pageName:String):PageDescription

 

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

Соответственно все страницы имеют уникальные именаpublic class Pages

{

public static const ABOUT:String = "about";

public static const ADMIN_EMAIL_TEMPLATE_EDIT:String = "adminEmailTemplateEdit";

public static const DOCUMENT_TRANSLATION:String = "documentTranslation";

}

и дескрипторы

Page 26: Enterprise flex pure mvc, slides, russian

PageDescription

pageName:String,

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

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

commandClass:Class)

  stateParams:Object = null, - редко встречающиеся доп.

параметры

pageTitle:String = null, } - часто встречающиеся доп.

параметры breadcrumbs:Array = null. … }

Page 27: Enterprise flex pure mvc, slides, russian

Вызов ViewPageCommandРегистрация команды

facade.registerCommand(BaseNotifications.VIEW_PAGE, ViewPageCommand);

Вызов команды активации страницы

var params:PageNotificationParams = new PageNotificationParams();

params.pageName = Pages.IMPORT_REPORT;

params.id = importReport.id;

params.documentType = importReport.dataType;

sendNotification(BaseNotifications.VIEW_PAGE, params);

PageNotificationParams var pageName:String;

var pageState:String;

var id:Number;

var backPageName:String;

var preloader:BasePreloaderMediator; - создается и добавляется в процессе открытия

Page 28: Enterprise flex pure mvc, slides, russian

Пример дескриптора страницыnew PageDescription( Pages.QUESTIONNAIRE,

QuestionnaireAnswerPreloader,

[QuestionnaireSlotHolderMediator, QuestionnaireAnswerMediator],

[QuestionnairesProxy, ProcessEditProxy, ProcessTypesListProxy, TimeScaleProxy],

[

new CommandDescription(SPNotification.FIND_NEW_QUEST, LoadQuestiannairCommand),

new CommandDescription(SPNotification.UPDATE_ASSET_QUEST, UpdateAssetCommand),

],

{ questionnaireComponentState: QuestionnaireComponentState.ANSWER },

"Questionnaire Registry"

)

Далее описание алгоритма работы ViewPageCommand …

Page 29: Enterprise flex pure mvc, slides, russian

Страница не

открывается

Страница не

открывается

Проверяет наличие дескриптора страницы

(если надо грузит нужный модуль)

load()

Медиаторы должны создать свои компоненты, разместить их в иерархии DisplayLists, сделать видимыми и подписаться на необходимые events.

pageDescriptor – ищем по имени страницыstateParams : {} – доп. набором параметров страницы не вошедшие в дескриптор (редко)viewParams : PageNotificationParams – параметры страницы, заполняемые при ее открытии (все которые нужны часто)

Создает и регистрирует необходимые прокси

Создает и запускает прелоадер

Закрывает текущую страницу

Регистрирует команды

validate() & препроцессинг

+

-

Создает (или достает из кеша) медиаторы

Активирует медиаторы.

После активации всех вызывается update()

Если создаются, то в следующем порядке: - Конструктор - Setup params (stateParams и viewParams) - create()

- отписывает от системы медиаторы - подчищает «временные» данные - отписывает медиатор от events компонентов - добавляет прелоадер во viewParams

Page 30: Enterprise flex pure mvc, slides, russian

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

Фрагмент кода вызова прелоадера при открытии страницыif(pageDesc.preloader != null)

{

setLoadingState(true);

registerProxies(); // for preloading

var preloaderMediator:BasePreloaderMediator = new (pageDesc.preloader)();

preloaderMediator.viewParams = params;

preloaderMediator.stateParams = pageDescriptor.stateParam;

preloaderMediator.callback = executeAfterPreload;

preloaderMediator.load(); 

Page 31: Enterprise flex pure mvc, slides, russian

BasePreloaderMediator var stateParams:Object;

var viewParams: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 - set preloader.errorKey before returning false value.

function validate():Boolean {

if(preloader.errorKey == null) {

// достаем нужное нам данное и проверяем

getPart("YYYid") – используем для проверки

}

return (preloader.errorKey == null);

}

Page 32: Enterprise flex pure mvc, slides, russian

Пример прелоадера «детям до 16» public class ManageGroupMembershipPreloader extends BasePreloaderMediator { override public function load():void {

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(); }   override public function validate():Boolean { if(super.validate()) { var contact:Contact = getPart(ContactProxy.CONTACT) as Contact; if(contact != null && contact.age < 16) setPreloaderError("Просмотр этой страницы не разрешен детям до 16"); return super.validate(); } }

Page 33: Enterprise flex pure mvc, slides, russian

МодульностьВ настоящее время система имеет: полторы сотни (150) основных страниц со связанными с ними rollover

формами, несколько десятков popup-форм некоторое кол-во подсистем,

работающих постоянно на экране, вызываемых по требованию пользователя или работающий в качестве «демонов» – daemon (ping, system messages) и «сервисов» (messages, multiple operations, progress indication etc.)

 

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

 

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

 

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

Page 34: Enterprise flex pure mvc, slides, russian

Соображения по поводу Модульности

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

RSL для этого использовать нельзя: приходилось бы вручную выбирать какие классы включать в эту библиотеку а

какие - нет

Флексовые модули для этого как бы не задумывались, но воспользоваться ими получилось: линкер mxmlc при компиляции модуля позволяет собрать все классы, по

цепочке зависимостей, есть возможность указать линкеру, что необходимо исключить классы, которые

уже есть в ядре приложения.

«Страничная» организация – основа сборки модуля. PageDescriptor – это узел для дерева линковки всех классов модуль подгружает ViewPageCommand в момент когда впервые понадобиться

страница содержащаяся в этом модуле узнает из справочника в каком модуле находится нужная страница

(moduleDescriptors.xml ) после загрузки модуля, все PageDescriptors из модуля добавляются в

PagesProxy

Page 35: Enterprise flex pure mvc, slides, russian

Структура иерархии модулей Module – единица компиляции и линковки ModuleDescription – содержит полный набор всех Page

Descriptors модуля PageDescriptionsXXX – логически сгруппированные наборы

дескрипторов страниц

moduleDescriptors.xml – справочник, содержащий информацию о том какая страница в каком модуле содержится flex-include-vo.xml – список всех VO системы для включения в ядро системы (решение проблемы регистрации VO для ремотинга) Соответствующие ANT скрипты. !!! НИКОГДА не включайте модули из среды Flash Builder!!!

Page 36: Enterprise flex pure mvc, slides, russian

 public function ModuleMain(){ super();  _moduleDescription = new ModuleDescriptionMain();  //NameUtils.registerServerClass(ContactTask);   initializeModule();}

 public function ModuleDescriptionMain(){ super("ModuleMain", [], [] .concat(PageDescriptionsMain.pageDescriptions) .concat(PageDescriptionsContacts.pageDescriptions) .concat(PageDescriptionsReporting.pageDescriptions) );}

Page 37: Enterprise flex pure mvc, slides, russian

public class PageDescriptionsResourcesAssets{public static const commonBreadcrumbs:Array = [Pages.R_A_VIEW_ROOT_RESOURCES];public static const commonProxies:Array = [ResourceTypeProxy, ParentListProxy, SessionDataProxy,AssetProxy, ProcessEditProxy, ProcessesListProxy ];public static const pageDescriptions:Array = [///////////////////////////////////////////// 

new PageDescription(Pages.UPDATE_RESOURCE_TYPE, PageState.ADD_EDIT_VIEW, ResourceTypeEditPreloader, Pages.R_A_VIEW_ROOT_RESOURCES, [ResourcesSlotHolderMediator, ResourceTypeEditMediator], [SessionDataProxy, AssetProxy, ProcessEditProxy], [ new CommandDescription(SPNotification.FIND_ASSET_FOR_DETAILS, LoadAssetCommand), new CommandDescription(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), 

new PageDescription(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) ] /////////////////////////////////////////////}

Page 38: Enterprise flex pure mvc, slides, russian

moduleDescriptors.xml <?xml version="1.0" encoding="UTF-8"?>

<Modules>

<Module name="ModuleMain">

<Pages>

<Page name="about"/>

<Page name="myTasksPage"/>

</Pages>

<Dependencies/>

</Module>

<Module name="ModuleAdministration">

<Pages>

<Page name="adminLogo"/>

<Page name="adminLanguageEditor"/>

<Page name="auditTrail"/>

</Pages>

<Dependencies/>

</Module>

</Modules>

Page 39: Enterprise flex pure mvc, slides, russian

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

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

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

1) в модуле делаем registerClassAlias(getClassServerName(classRef), classRef);

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

<?xml version="1.0"?> <flex-config> <includes append="true"> <symbol>com.os.sp.domain.messaging.MessagesGroup</symbol> <symbol>com.os.sp.domain.messaging.SmsCostConfig</symbol> <symbol>com.os.sp.domain.integrity.InvalidRecord</symbol> </includes> </flex-config>

Page 40: Enterprise flex pure mvc, slides, russian

Фрагмент 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-config filename="${FLEX_LOCAL_CONFIGURATION}"/> </mxmlc>  

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

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

Page 41: Enterprise flex pure mvc, slides, russian

КОНЕЦ

[email protected]

Page 42: Enterprise flex pure mvc, slides, russian

НО

Page 43: Enterprise flex pure mvc, slides, russian

ОСТАЛОСЬ НЕ ОХВАЧЕННЫМ

Взаимодействие View Components и Mediators

Шаблон «страницы» Интерфейс «страничного» View Component Обмен данными между медиатором и View

компонентом. Состояние «редактирования» (Editing state) Обработка нажатий кнопок (Buttons) Обработка других команд (пример –

Chevrons)

Page 44: Enterprise flex pure mvc, slides, russian

А ТАКЖЕ

Базовые классы медиаторов Медиатор формы Медиатор листа Медиатор попапа

Подсистема Proxy-Delegate-Preloader Локализация приложений

Page 45: Enterprise flex pure mvc, slides, russian

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

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

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

Page 46: Enterprise flex pure mvc, slides, russian

Способы создания и связывани компонента с медиатором. protected function setupMediator(…) 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

Page 47: Enterprise flex pure mvc, slides, russian

Особенности реализации протокола взаимодействия слот-холдер медиаторов с их клиентами. override public function listNotificationInterests():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 ); }

  override public function handleNotification(notification:INotification):void { super.handleNotification(notification); … }

Page 48: Enterprise flex pure mvc, slides, russian

private function defaultSlotHolderNotificationHandler(notification:INotification):void

{

if(slots && slots[notification.getType()]) {

var desc:SlotViewComponentDescription = notification.getBody() as SVCD;

var component:UIComponent;

component = getViewComponentFromSlot(desc.viewComponentSlot, desc.viewComponentName);

switch(notification.getName()) {

case BaseNotifications.SLOT_VIEW_COMPONENT_SHOW:

FlexUIComponentsUtils.showViewComponent(component, true);

break;

case BaseNotifications.SLOT_VIEW_COMPONENT_HIDE:

component.visible = false;

break;

case BaseNotifications.SLOT_VIEW_COMPONENT_ADD:

addViewComponentToInternalSlot(desc);

desc.viewComponent = null; // mark viewComponent as added

break;

case BaseNotifications.SLOT_VIEW_COMPONENT_REMOVE_BY_NAME:

removeViewComponentFromSlotByName(desc);

break;

case BaseNotifications.SLOT_VIEW_COMPONENT_FIND:

desc.viewComponent = component;

break;

}}}

Page 49: Enterprise flex pure mvc, slides, russian

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

* Register handler for Notification - works just like addEventListebner. * It doesn't depend on registerMediator/removeMediator !BE AWARE! function addNotificationListener(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! function removeNotificationListener(notificationName:String):void { org.puremvc.as3.core.View.getInstance().removeObserver(notificationName, this ); }

Page 50: Enterprise flex pure mvc, slides, russian

Пример использования: * Try to add view component in appropriate external slot. If there isn't * appropriate slot then start waiting for SLOT_CREATION_COMPLETE. function addViewComponentToExternalSlot():void { var desc:SlotViewComponentDescription = new SlotViewComponentDescription viewComponentName, viewComponentSlot, viewComponent as UIComponent );   var addNotification:INotification = new Notification( BaseNotifications.SLOT_VIEW_COMPONENT_ADD, desc, viewComponentSlot);   facade.notifyObservers(addNotification);   if(desc.viewComponent != null) // его бы обнулили если бы он был найден { addNotificationListener(BaseNotifications.SLOT_CREATION_COMPLETE, handleSlotCreationCompleteNotificationToAddViewComponent); } }