Фев 14 2010

Знакомство с MVCS фреймворком Robotlegs

Рубрика: ActionScript 3.0Diestro @ 21:28

Впервые об этом фреймворке я услышал на BURAFPUG, прошедшем 6 февраля 2010 г. После некоторого изучения документации я пришел к выводу, что Robotlegs действительно очень интересный фреймворк.

Я не буду здесь рассказывать о конкретной реализации простого приложения типа Hello World, т.к. примеров приложений вполне достаточно на сайте фреймворка.

Robotlegs это MVCS фремворк реализующий паттерн MVC с добавлением еще одного элемента – Services, использующегося для реализации взаимодействия с «внешним миром», будь то Web-сервисы, файловая система, базы данных, взаимодействие с другими Flash-приложениями через Local Connection и т.п.

Внедрение зависимостей (Dependency Injection)

Современные фреймворки, базирующиеся на паттерне MVC теми или иными способами поддерживают реализацию принципа Inversion of Control (Ioc) или Dependency Injections (DI). Robotlegs также основан на этом принципе.

Для чего нужно использование паттерна Dependency Injection? ООП приложение состоит из классов. Классы могут получать доступ к другим классам имея ссылки на них. Они взаимодействуют друг с другом, используя эти ссылки. Смысл Dependency Injection – уйти от высокой связанности приложения, заменив описание взаимодействия между конкретными классами на интерфейсы. Т.е. класс X будет использовать не класс Y а реализациею его интерфейса I. В результате мы получаем низко связанное приложение, классы которого знают только о интерфейсах для работы с другими классами. Например в приложении для работы с почтой мы будем работать с интерфейсом IMailLoader, вызывая метод load(), а не с конкретной реализацией класса IMAPMailLoader. В этом случае IMAPMailLoader будет легко заменить на POPMailLoader,реализующий интерфейс IMailLoader или на любой другой класс реализующий нужный интерфейс.

В Robotlegs DI реализован с помощью SwiftSuspenders. Это легковесный DI фреймворк для реализации этого паттерна посредством метатегов [Inject].

Работая с Robotlegs с классом наследуемом от Context (о нем я расскажу ниже) мы имеем доступ к переменной injector. Это экземпляр класса, реализующего функционал фреймворка SwiftSuspenders. injector – это менеджер внедряющий нужный экземпляр класса в классы нашего приложения.

Возвращаясь к примеру с почтовым сервисом реализация DI с помощью Robotlegs выглядит следующим образом:

1
2
//Когда запрашивают  интерфейс IMailLoader вернуть экземпляр класса  IMAPMailLoader
injector.mapClass(IMailLoader, IMAPMailLoader);

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

1
2
[Inject]
public var mailLoader:IMailLoader;

В результате переменная mailLoader будет содержать экземпляр класса IMAPMailLoader.

Если же мы напишем:

1
2
injector.mapClass(IMailLoader, IMAPMailLoader, "IMAP");
injector.mapClass(IMailLoader, POPMailLoader, "POP");

В нашем классе мы можем задать name, для инстанцирования нужной нам реализации:

1
2
[Inject(name="POP")]
public var mailLoader:IMailLoader;

В результате переменная mailLoader будет содержать экземпляр класса POPMailLoader.

Создавая карты с помощью injector можно также внедрять конкретные экземпляры классов (mapValue), классы «одиночки» (mapSingleton) и пр. Подробнее об этом написано в документации Robotlegs.

Немножко разобравшись с реализацией DI в Robotlegs перейдем к реализации MVCS архитектуры.

Контекст

Сердцем фреймворка Robotlegs является класс Context, от которого собственно и наследуется наш главный класс приложения. В этом классе задаются основные связи между компонентами приложения.

Карты команд

С помощью commandMap задается какую команду нужно вызывать при возниковении того или иного события.

1
commandMap.mapEvent(MyEvent.SOME_HAPPENED, MyCoolCommand, MyEvent);

Карты отображения

Так же как и PureMVC в Robotlegs для взаимодействия с view-компонентами используются посредники, называемые медиаторами. View-компоненты и их медиаторы сопоставляются с помощью mediatorMap.

1
mediatorMap.mapView(MyAwesomeWidget, MyAwesomeWidgetMediator);

Интересной особенностью медиаторов является их автоматическое инстанцирование только в случае добавления view-компонента, связанного с этим медиатором, в список отображения,что впрочем можно отключить во время задания правила для mediatorMap. Существует еще и viewMap, о котором в официальной документации не сказано ничего, но насколько я понял он используется для «внедрения» view-компонентов в классах приложения, т.е. является полным аналогом прямого использования injector.

Карты внедрения (иньекций)

Здесь описываем все классы или их экземпляры, которые необходимо «внедрять» в классы нашего приложения посредством использования метатега [Inject]. В частности здесь мы описываем наши классы с данными и сервисами необходимыми для реализации MVCS:

1
2
injector.mapSingleton( ApplicationModel );
injector.mapSingletonOf( IGalleryImageService, GalleryImageService );

Все классы описанные с помощью commandMap и mediatorMap автоматически подготавливаются фреймворком для «внедрения» в классы приложения.
Таким образом в нашем главном классе приложения перед запуском мы конфигурируем все необходимые компоненты и взаимодействия.

События

Для системы событий Robotlegs использует «родные» события Flash-плеера. Для их распространения внутри фреймворка используется следующий синтаксис:

1
dispatch(new ContextEvent(ContextEvent.STARTUP));

Чтобы слушать события используется следующий синтаксис:

1
eventMap.mapListener(dispatcher, ContextEvent.STARTUP, startupHandler);

Либо как уже было сказано выше во время конфигурации приложения можно указать на какое событие должна запускаться та или иная команда:

1
commandMap.mapEvent( ContextEvent.STARTUP, StartupCommand, ContextEvent);

Распространять и слушать события могут далеко не все фигуранты фреймворка. Кратко рассмотрим «Актёров» Robotlegs (MVCS).

Модель и сервисы (M и S)

Я позволю себе объединить описание этих двух составных частей фреймворка в одном месте, так как оба этих компонента должны наследоваться от класса Actor. Для фреймворка не имеет значение модель это или сервисы, это просто «Актер», наделить их функционалом должен уже разработчик.

Для того чтобы иметь доступ к модели или классу сервиса из других классов фреймворка достаточно будет написать [Inject] перед объявлением переменной. Например если класс с данными называется ApplicationModel, то в классе, где необходимо будет его использовать, достаточно написать:

1
2
[Inject]
public var myModel:ApplicationModel;

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

Наследники класса Actor могут посылать события приложению используя метод dispatch.

Отображение (V)

Как правило каждый компонент отображения в Robotlegs состоит из двух элементов – cобственно компонента отображения и элемента, являющегося частью фреймворка – медиатора. Медиатор является посредником между компонентом отображения и фреймворком. Его основная задача информировать приложение о действиях пользователя и наоборот – изменять элементы отображения в соответствии с изменениями в приложении.

Медиатор должен наследоваться от класса Mediator. Элемент отображения связанный с медиатором доступен в переменной viewComponent. Медиатор имеет доступ к dispatch() и eventMap, а это значит что он может как распространять так и слушать события внутри приложения.

Для инициализации медиатора крайне не рекомендуется пользоваться конструктором. Для этого существует метод onRegister(), который необходимо переопределить и писать код инициализации в нем.

Для доступа к модели достаточно внедрить класс модели с помощью метатега [Inject] , так как это было описано выше.

Контроллер (С)

Функционал контроллера реализуется в Robotlegs посредством вызова команд. Класс команды должен наследоваться от класса Command. Команда создается только на время выполнения и после выполнения попадает в Garbage Collector. Команда появляется как результат возникновения события. Код, который должен выполнить команда должен быть помещен внутри переопределенного метода execute(). Сопоставления команд событиям происходит в commandMap Контекста приложения. Тот же самый commandMap доступен и внутри любой из комманд.

Доступ к модели организуется так же как и в классах отображения.

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

1
2
[Inject]
public var event:MyCustomEvent;

Команда может также посылать события приложению используя метод dispatch.

Кратко резюмируя хотелось бы сказать что реализация Robotlegs действительно очень интересная и заслуживает внимания. В чем то она похожа на PureMVC, об этом же говорит и автор Robotlegs. Однако в Robotlegs иначе организована система событий, не нужно писать switch/case в обработчиках событий, как это реализовано в PureMVC. Достаточно подписаться на нужное событие и назначить метод обработчик, так как мы это привыкли делать со стандартными событиями Flash. По другому организовано и взаимодействие между компонентами приложения. В отличии от PureMVC в Robotlegs для доступа к другим компонентам приложения уже не используются retrieveProxy, retrieveMediator и т.п., а используется метатег [Inject].

Tags: ,

3 комментария »

  1. Комментарий от switcher — 17 февраля 2010 @ 10:44

    Хотелось бы еще ознакомится с метатегом [Inject]. Все поиски не дали никакого результата, к сожалению. Но, думается, что это часть работы компилятора flex SDK (как и другие метатеги), т.е. возможность встроенная, а значит – может и должна иметь описание.
    Не знаете: где можно ознакомится?

  2. Комментарий от Diestro — 17 февраля 2010 @ 11:22

    Метатег [Inject] сам по себе не является “частью работы” компилятора Flex SDK. Этот тег, как и написано выше – часть фреймворка SwiftSuspenders. По ссылке можно с ним ознакомиться. В посте также приведена ссылка на документацию Robotlegs. Там по тегу [Inject] тоже очень много сказано.

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

  3. Комментарий от razukrashka — 21 февраля 2010 @ 16:15

    Спасибо за вольный перевод. Сейчас как раз то же рассматриваю robotlegs, в качестве замены более громоздким микроархитектурам.
    Но смелости писать статьи пока не хватает. У вас не плохо получилось.

RSS лента комментариев к этой записи. TrackBack URL

Оставить комментарий

Comment Spam Protection by WP-SpamFree