Tag Archive for 'MVC'

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 компонентиков.

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

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

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

Я уже давно стою между чистым флэшем и флексом. С одной стороны, для флекса есть 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.

Скачать

Переход на PureMVC

Мне стыдно признаться, но совсем недавно лишь только я решил все-таки потрогать фреймворк PureMVC. Тогда я писал модульный плеер и нормально справлялся со своим MVC решением. Но, наткнувшись на некоторые ограничение своей архитектуры, а обнаружил, что PureMVC не содержит этих ограничений. Тогда я начал переписывать плеер на нем.

И тут буквально вчера простенький image slider для очередного сайта я решил переписать с использованием PureMVC. Я доволен. Подход MVC позволяет избавиться от многих трудностей разработки, а данный фреймворк хоть и немного отходит от традиционного определения MVC, позволяет при развитии проекта далее надеть мягкие накладки на разбросанные по саду грабли. А именно, я удивился как легко было сделать автоматический скроллер по таймеру, который обновляет оба компонента: картинки и меню.

В старой русской методологии программирования “Через Ж#пу” (звиняюсь) такое изменение потребовало бы некоторого количества усилий и повлекло бы с собой некоторое количество багов.

Картирка кликабельна.