Flex i klasy prywatny
Bardzo lubię korzystać z prywatnych zagnieżdżonych klas w języku Java. Niestety, nie potrafię ich znaleźć w Action Script. To duża strata dla języka programowania. To prawie tak, jakby w języku polskim nie było przymiotników;). Problemy, które chciałbym rozwiązać prywatną klasą rozwiązuję więc w Flex w następujący sposób. Tworzę nowy plik z klasą internal class. Rzeczy, które powinny być private robię jako “interna”. Czyli w Flex mam dwie klasy w osobnych plikach lecz jednej z nich używam jako prywatnej. Właściwości języka AS3 bronią mnie przed użyciem moje klasy prawie prywatnej poza pakietem. Na przykład:
public interface INetStreamClient
{
function onMetaData(info:Object=null):void;
[…]
Czy ktoś lubi dynamiczne klasy do implementowania netStream.client – bo ja nie… (takie dynamiczne klasy wymagają zbyt wielu komentarzy). Dlatego stworzyłem ten interfejs z wszystkimi metodami zwrotnymi serwera. Następnie każda implementacja rozszerza ten interfejs. Domyślna implementacja to logowanie:
public class TracerNetStreamClient implements INetStreamClient {
public function onMetaData(info:Object=null):void {
trace(“NetStreamClient.onMetaData: “ + info + ” duration: “ + info.duration);
}
[…]
Powoli dochodzę do sedna sprawy. Mam klasę która pomaga mi odtwarzać filmy. Jednym z pól tej klasy jest “INetStreamClient”. W aplikacji jakieś inne obiekty mogą używać mojego pomocnika do odtwarzania filmów, podając mu swoja implementację klienta strumieni. Więc mam coś takiego:
public class MoviePlayer
{
[Inspectable]
public var netStreamClient:INetStreamClient;
private function createNetStream():void {
_netStream = new NetStream(netConnection);
_netStream.client = new MoviePlayerNetStreamClient(this, netStreamClient == null ? new TracerNetStreamClient() : netStreamClient );
[…]
I właśnie teraz bardzo mi zabrakło zagnieżdżonej klasy prywatnej. Chciałem wzbogacić działanie metody onMetaData. Potrzebuję klasy Proxy, której będę potrzebował tylko w tym miejscu, i która powinna mieć dostęp do prywatnych możliwości klasy MoviePlayer. Niestety w Flex tego nie ma. Dlatego radzę sobie na około tworząc klasy internal. Moje prywatne Proxy wygląda więc tak:
internal class MoviePlayerNetStreamClient implements INetStreamClient {
private var _moviePlayer:MoviePlayer;
private var _netStreamClient:INetStreamClient;
public function MoviePlayerNetStreamClient(moviePlayer:MoviePlayer,netStreamClient:INetStreamClient)
{
super();
_moviePlayer = moviePlayer;
_netStreamClient = netStreamClient;
}
public function onMetaData(info:Object=null):void {
var d:Number = info["duration"];
_moviePlayer.addDuration(d);
return _netStreamClient.onMetaData(info);
}
[…]
Jak widać, klasy prywatne mogą przydać się do implementacji wzorca projektowego dekorator. Ich brak kompensuję klasą internal. Klasa internal widoczna jest w obrębie pakietu i trzeba ją umieścić w osobnym pliku.