Tag Archive for 'IoC'

Dependency Injection

Dependency Injection и принцип Inverse of Control в программировании используются уже давно. Я как понял DI — это термин, который Мартином Фаулером используется для обозначения того же IoC. Что же это такое и как его использовать нам, простым флэш разработчикам.

Все просто. Основная идея — при создании объекта ему даются (инжектируются) уже готовенькие объекты, в которых он нуждается (зависимости). Каждый из нас, интуитивно полагая, что это гуд, использовал Dependency Injection в той или иной мере. Вот простой код.

public class One{
    public function One( two: ITwo )
    {
        this.two = two;
    }
}

public class Two implements ITwo {
    ...
}

new One( new Two() );

Как видно, объекту класса One мы передаем объект с интерфейсом ITwo при создании. Перед нами простой пример так называемого Constructor Injection. Также есть Property Injection, когда класс предоставляет public свойство или сеттер, через который ожидает получить некоторый объект, в котором нуждается. Идея проста до безобразия и позволяет проще переиспользовать классы, которые друг на друга не завязаны.

Противоположный подход — создавать все dependency внутри класса, при этом классы становятся привязанными друг к другу, что усложняет внесение изменений.

Интереснее же все становится, когда на сцену выходит IoC Contaner. Под контейнером понимается некоторое пространство для объектов, который по определенным правилам эти объекты сам конфигурирует и сам подставляет dependencies куда и кому нужно. Проще говоря, некоторый фреймворк, который сам соображает (с нашими подсказками) как собрать те или иные объекты и какие зависимости им нужны.

AS3.

Речь пойдет о чисто AS3 проектах. Они обычно небольшие в отличие от Flex проектов, которые можно сравнить с Java Enterprise проектами. Если в Java существует толпа IoC фреймворков (как я понимаю самый популярный Spring Framework), то для ActionScript до недавнего времени все было как-то грустно. Конечно, AS3 язык гораздо моложе, чем Java, скажете вы.

Между тем я случайно наткнулся на Syringe, который мимикрирует со Spring, повторяя метод конфигурации через XML, но последняя версия выпущена в бородатом 2006м. Видим, что какие-то попытки перенести функциональность Spring на ActionScript3 велись, но не были поддержаны сообществом, потому что сообщество не было к этому готово. И, конечно же, потому, что большинство AS3 проектов небольшие, на одного программиста и дизайнера.

Какое-то время уже существует официальный Spring ActionScript (бывший Prana). Этот фреймворк вроде бы развивается и сейчас остановился на версии 0.8.

Favour of the month безусловно является Parsley, версия 2 которого радикально изменилась и поддерживает множество вкусных фишек. В том числе и для pure AS3 проектов.

Применение.

Как-то давно на основе Parsley 1.* я набросал себе небольшой фреймворк, который использую при создании и конфигурировании видео плееров и фото галерей.

Значит, допустим у нас есть видео плеер с архитектурой MVC. Разные проекты предусматривают разное расположение визуальных элементов и разные функции. Чтобы каждый раз не копипастить все это, делаем максимально decoupled компоненты и собираем их IoC контейнером при помощи XML конфига.

Вот пример такого конфига для одного из плееров. Видим команды контейнеру по сборке объектов. Любую можно убрать или добавить и плеер пересоберется подругому. Порой, даже не нужно перекомпилировать проект. Конечно, данный пример не использует таких мощных фишек контейнера, как инжектирование по типу, просто мой старенький этого не умеет.

<?xml version="1.0" encoding="UTF-8"?>
<container>
<commands>
<!-- Скин плеера -->
<object name="skin" class="com.qq.videoplayer.skin.PPSkin" />
<!-- Сам плеер -->
<object name="player" class="ru.valyard.media.mediaplayer.VideoPlayer">
<constructor-args>
<object ref="skin" />
</constructor-args>
<!-- Контейнер для контролов -->
<view name="controls" class="ru.valyard.upa.mvc.views.FixedContainer" />
<!-- Компонент показывающий картинку до проигрывания -->
<view name="preview" class="ru.valyard.media.mediaplayer.views.controls.PreviewView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Анимашка, которая моргает во время буферизации -->
<view name="buffering" class="ru.valyard.media.mediaplayer.views.controls.BufferingView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Большая кнопка Play в центре -->
<view name="bigPlay" class="ru.valyard.media.mediaplayer.views.controls.BigPlayButton" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Экран как видео проигралось -->
<view name="stopView" class="ru.valyard.media.mediaplayer.views.controls.StopView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Верхние контролы -->
<view name="dynamicpanel2" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">10</property>
<property name="xRule">5</property>
<property name="inactiveYRule">-70</property>

</view>
<view name="top" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel2">
<constructor-args>
<int>0</int>
</constructor-args>
</view>
<!-- Fullscreen -->
<view name="fullscreen" class="ru.valyard.media.mediaplayer.views.controls.FullscreenButtonView" parent="top"/>
<!-- Share -->
<view name="shareButton" class="ru.valyard.media.mediaplayer.views.controls.ShareButtonView" parent="top"/>
<view name="popout" class="ru.valyard.media.mediaplayer.views.controls.PopoutView" parent="top"/>
<!-- Основные контролы -->
<view name="dynamicpanel" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">H-42</property>
<property name="inactiveYRule">H</property>
</view>
<view name="panel" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel">
<constructor-args>
<int>2</int>
</constructor-args>
</view>
<!-- Watermark -->
<view name="watermark" class="ru.valyard.media.mediaplayer.views.controls.SymbolView" parent="dynamicpanel">
<constructor-args>
<string>Watermark</string>
</constructor-args>
<property name="xRule">W</property>
</view>
<!-- Play/pause buttons -->
<view name="playpause" class="ru.valyard.media.mediaplayer.views.controls.PlayPauseView" parent="panel"/>
<view name="prev" class="ru.valyard.media.mediaplayer.views.controls.PreviousView" parent="panel"/>
<view name="next" class="ru.valyard.media.mediaplayer.views.controls.NextView" parent="panel"/>
<view name="line" class="ru.valyard.media.mediaplayer.views.controls.LineView" parent="panel">
<property name="widthRule">W-playpause.width-sound.width-next.width-prev.width</property>
<property name="leftSpace">1</property>
<property name="topSpace">12</property>
<property name="rightSpace">4</property>
<property name="scrollerDist">6</property>
</view>
<!-- Sound on/off button -->
<view name="sound" class="ru.valyard.media.mediaplayer.views.controls.HorizontalSoundView" parent="panel"/>
<!-- Share window -->
<array name="sizesArray">
<string>640x480</string>
<string>480x360</string>
<string>320x240</string>
</array>
<view name="shareView" class="ru.valyard.media.mediaplayer.views.controls.ShareView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
<property name="sizes" ref="sizesArray"/>
</view>
<!-- Ad -->
<view name="ad" class="ru.valyard.media.mediaplayer.views.thirdparty.TremorMediaAdsView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
<property name="id">123</property>
</view>

<module class="com.qq.videoplayer.modules.PlayCount" name="playcount">
<constructor-args>
<string>http://qq.com/qq.php</string>
</constructor-args>
</module>

<!-- Debug actions -->
<action class="ru.valyard.media.mediaplayer.actions.TestAction" name="*" priority="3" />

<!-- XML loader class -->
<object name="loader" class="ru.valyard.media.mediaplayer.loaders.PlaylistXMLLoader" />
<method name="registerLoader">
<object ref="loader" />
</method>

<!-- Embed HTML template -->
<property name="embedHTMLTemplate">
<![CDATA[<object width="%W%" height="%H%"><param name="movie" value="http://www.qq.com/swfs/embed.swf?id=%ID%"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.qq.com/swfs/embed.swf?id=%ID%" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="%W%" height="%H%"></embed></object>]]>
</property>
<!-- -->
<property name="pageURLTemplate">
<![CDATA[http://www.qq.com/video/%PAGE%]]>
</property>
<!-- -->
<property name="dataURLTemplate">
<![CDATA[http://www.qq.com/xml/%DATA%]]>
</property>

<property name="mediaURLTemplate">
<![CDATA[http://www.qq.com/videos_final/%URL%]]>
</property>
</object>
</commands>
</container>

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

Плюсы.

Про конфигурирование плеера я уже сказал. Это несомненно плюс. Этот подход позволяет максимально разделить используемые объекты друг от друга и легко переиспользовать их в других проектах. В осноном, избавляет от неободимости писать кучу конфигурационного кода. Конечно, приведенный здесь конфиг не является идеальным примером. СтОит почитать хелп Parsley, который имеет куда более продвинутые способы конфигурирования.

Минусы.

Есть какая-то граница, при переходе которой конфигурирование контейнера превращается в более time consuming процесс, чем если бы я просто сел и руками все написал. Конечно, IoC позволяет создать задел на будущее для возможных исправление и переработок, но как показывает практика, часто нужно просто быстренько наклепать код и избавиться от него. В небольших проектах смысла использовать особо нет, если не имеет место сборка маленьких reusable компонентиков.

Революция сейчас. jetBRAINS выпустила Meta Programming System

MPS вышел, господа! И странно, что по этому поводу в интернетах как-то все еще тихо. Ведь мы имеем дело с самой настоящей революцией в мире программостроения. Видимо, как в случае с переходом к OOP, переход к LOP будет медленным и болезненным.

Что за революция и что за LOP, спросите вы? Про Language Oriented Programming очень хорошо написано на английском здесь, про сам MPS здесь. А если коротко, то идея сама по себе проста — все давно знакомы с концепцией DSL (Domain-Specific Languages), ставим ее на новый уровень и получаем инструмент для создания новых, расширения существующих и с удобным кастомным IDE для разработки на этих языках.

Работая сразу с Абстрактным Синтаксическим Деревом (в которые любой текст программы все равно перегоняется при компиляции), а не с текстом, MPS позволяет создавать нетекстовые редакторы или использовать разного рода интересные контролы при редактировании текстовых программ. А главное, как часто вам хотелось бы расширить ваш любимый язык новыми конструкциями для ускорения разработки? Пришлось бы расширять грамматику языка, а что если бы кто-то другой придумал еще одно расширения и оба они бы ломали грамматику? MPS позволяет делать это изящно, но конечно сложновато, и нужно какое-то время чтобы научиться и понять что же ты толком делаешь. А взять, например, множество фреймворков и библиотек, которые по сути и являются этими DSL в узких областях. Почему бы их не переделать в расширение языка?

В общем, всем читать и качать MPS.

Каким боком тут я и почему я рад этому событию? Потому что замечательный человек, который показал мне какое-то время назад MPS, это Евгений Потапенко. И он уже долгое время пишет интересный редактор ActionScript 3 на этой системе, и раз за разом удивляет интересными скринкастами (описания спер у Ивана Дембицкого, надеюсь он не очень зол на меня за это):

Шаблоны для геттеров/сеттеров и филдов
http://www.potapenko.com/tmp/screencasts/templates.flv

Как делаются override method с автоматическим добавлением ключевого слова override и навигация
http://www.potapenko.com/tmp/screencasts/override.flv

Помощник по именованию методов/переменны/полей
http://www.potapenko.com/tmp/screencasts/naming.flv

Основная фича редактора – расширение языка – тут добавил ENUMS в AS
http://www.potapenko.com/tmp/screencasts/enums.flv

Ну редактор и что? А то, что детально изучив MPS, я прямо сейчас вижу, как в ActionScript легко добавляется AOP, как Spring-like IoC фреймворк с конфигурацией через XML файлы переделывается в простой DSL. Даже мои хелпер классы для создания видеоплееров и простых сайтов-визиток умещаются в DSL.

The future is now, господа!

Изобретать ли свой велосипед

Значит, предлагаю тему для обсуждения.

Моя область деятельности сейчас — это промо сайты и разнообразные виджеты в том числе видео.

Я уже давно стою между чистым флэшем и флексом. С одной стороны, для флекса есть Mate, который весьма интересен, во флексе есть хорошие контролы и компоненты, флекс сам по себе предоставляет больше возможностей для програмера. С другой стороны, флекс тянет за собой флекс фреймворк и его ограничения, плюс, мне так и не удалось на флексе, без того чтобы поиметь солидную головную боль, сделать что-то повседневное типа хорошо так анимированного флэш сайта.

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

Читая время от времени новости от Adobe, я вижу, что связка Catalyst + Gumbo нацелена как раз на смещение равновесия в сторону флекса.

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

Прошу высказать свои соображения.

onEnterFrame.ru #5

Первый посленовогодний выпуск подкаста. На этот раз темы следующие:

  • Новый год, новые перспективы
  • Немного о кризисе, банкротстве Circuit City и Обаме
  • Как 20го числа умер CS4
  • Фреймворк, Parsley, Spring Actionscript (ex-Prana), IoC, DI, MVC, AOP и другие страшные слова
  • AsUnit и асинхронные тесты
  • TheFWA и ecodazoo.com
  • TheFWA и книжка
  • TheFWA и valyard.ru
  • С кем дальше записывать подкасты?

Ссылки по теме:

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

Скачать

FrameworkQuest

Отличный цикл статей на InsideRIA под общим названием FrameworkQuest. Рекомендую к прочтению тем, кто не знает чем отличается IoC ot PureMVC и чем закусывать Cairngorm. Чрезвычайно интересно. И не только флексерам.