Tag Archive for 'java'

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

Визуализация наследования

Joa Ebert у себя в блоге запостил забавную штукупрограммка для экспорта цепочки наследования из скомпиленного SWF + визуализация этого барахла через Graphviz.

Опробовал на одном из своих плееров. С удивлением узнал, что импортнутые из SWC мувики имеют тип FlexSprite и тянут за собой немного флексового барахла.

Graphviz, конечно, полное убожество. Нельзя даже двигать ноды, чтобы удобненько распечатать.

Кстати, если на маке у кого не обновилась JVM до 1.6, то тут написано как это сделать.

Куда идем мы с Пятачком…

Python, Ruby или все-таки Java?

Aspect Oriented Programming

Изучая документацию по Spring, наткнулся на реализацию концепции AOP. Об этой парадигме мне когда-то что-то рассказывали, но я особо этому значению не придал. Сейчас же, прочитав достаточно информации, я немножко вдохновился и стал смотреть что по этому поводу предлагает ActionScript.

А оказалось, что ничего.

An issue right now is that you can’t let an object implement an interface or a set of interfaces at runtime.

ActionScript would really benefit from having a dynamic proxy mechanism, similar to the Proxy class in Java: http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html

This could be used for several interesting and powerful new concepts:
- adding new behavior to an object by proxying it with extra interfaces
- mock objects for unit testing
- Aspect Oriented Programming
- …

Если в ActionScript 2 и тем более в 1 мы могли переопределять методы объектов, сохраняя старые, то здесь такой трюк уже не проходит. А жаль.

И еще ant + mac

Меня тут Константин просветил, оказывается ant идет с mac осью.
Но версия 1.7.0, а я поставил 1.7.1. Так что какая-то польза есть.

Надо бы посмотреть что еще идет, а то пытался сообразить как JDK поставить, а оказывается оно там уже есть. Ужос.