Einführung in das Robotlegs ActionScript-Framework

robotlegs-as3-framework

Robotlegs ist ein schlankes Open Source ActionScript-Framework. Es kann sowohl in reinen ActionScript- als auch in Flex- bzw. AIR-Projekten verwendet werden.

Robotlegs is a pure AS3 micro-architecture (framework) with a light footprint and limited scope. Simply put, Robotlegs is there to help you wire your objects together. […] By promoting loose coupling and avoiding the use of Singletons and statics in the framework Robotlegs can help you write code that is highly testable.

Der Einstieg in Robotlegs fällt dank der guten Dokumentation, einfachen Beispielen und hübschen Diagrammen leicht. Deshalb gibt es in diesem Artikel eine kurze Übersicht, was Robotlegs auszeichnet. Darüber hinaus erläutere ich die wichtigsten Konzepte anhand eines MVC-Beispiels.

MVCS Reference Implementation

Robotlegs bringt eine vorschlagene Referenzimplementierung des Model-View-Controller-Prinzip (MVC), erweitert um den zusätzlichen Bereich „Service” für externe Datenanbindungen (MVCS). Die einzelnen Bereiche schildere unten bei der Erklärung des Beispiels.

robotlegs-mvcs

Dependency Injection

Robotlegs bietet die Möglichkeit, Variablen über die Deklarierung in den Metadaten zu „injizieren“ (Dependency Injection).

[as]
[Inject]
public var statsModel:StatsModel;
[/as]

Events

Robotlegs verwendet das gewohnte Eventsystem von Flash. Man also entweder bereits vorhandene Events verwenden oder die Event-Klasse erweitern. Ebenfalls interessant (z.B. im Vergleich zum Mate Framework): Es können auch Events von Objekte erfasst werden, die sich nicht in der Display List befinden. Auch wird das Event Bubbling nicht vorausgesetzt.

Hello-World-Beispiel mit Flash (AS3)

hello-flashIm folgenden erläutere ich kurz die wichtigsten Konzepte. Das Beispiel stammt aus dem Demobundle und heißt „Hello Flash” (Beispiel und Quellcode.

Context

Startpunkt der Anwendung ist die Klasse HelloFlash.as. Dort wird ein neues Objekt der Klasse HelloFlashContext erstellt.
[as]
context = new HelloFlashContext(this);
[/as]

Die Klasse HelloFlashContext erbt von Context und beinhaltet grundlegende Funktion (z.B. die Initialisierung der Anwendung). Sie sorgt also quasi für den nötigen „Kontext“, in dem die Anwendung läuft.

[as]
public class HelloFlashContext extends Context
{
public function HelloFlashContext(contextView:DisplayObjectContainer)
{
super(contextView);
}

override public function startup():void
{
// HIER DIE INITIALISIERUNGEN DURCHFÜHREN

// And we’re done
super.startup();
}
[/as]

Die entsprechenden Initialisierungen führt man durch Überschreiben der Funktion startup() durch.

Eine Aufgabe dort kann sein, ein Datenmodel vorzubereiten, dass in allen anderen Klasse über [Inject] eingefügt werden kann. Dadurch wird gewährleistet, dass alle Klassen auf demselben Datenobjekt arbeiten. Dies geschieht z.B. mit injector.mapSingleton(StatsModel).

Eine andere Aufgabe kann sein, ein Objekt zur Bühne (innerhalb dieses Contexts) hinzuzufügen. Dies funktioniert z.B. mit contextView.addChild(new Readout()).

Zwei weitere Möglichkeiten für die Funktion startup, die im Anschluss erklärt werden, ist das Zuordnen von Events für den Controller (Command) und die Verknüpfung von Views mit dem dazugehörigen Mediator.

View und Mediator

Die View, also das reine Frontend (z.B. die Klasse Ball), wird mit einem dazugehörigen Mediator (z.B. Klasse BallMediator) verknüpft. Dies geschieht mit der Zeile mediatorMap.mapView(Ball, BallMediator) in der Funktion startup (siehe oben).

Der Mediator enthält quasi die Logik für die View. Er hört sowohl auf Events der View (z.B. einen Buttonklick) als auch auf Events, die vom Framework kommen (z.B. dass eine Änderung in der View durchgeführt werden soll).

Mit eventMap.mapListener(view, MouseEvent.CLICK, onClick) wird im Beispiel auf einen Mouseklick auf das Viewobjekt reagiert. Wichtig: Das Mapping im Mediator muss innerhalb der Funktion onRegister():void geschehen und nicht im Konstruktur!

Mit eventMap.mapListener(eventDispatcher, HelloFlashEvent.BALL_CLICKED, onSomeBallClicked) wird auf das Event des Frameworks reagiert (nämlich vom zentralen eventDispatcher).

Controller und Commands

Die Commands sind zustandslos und erledigen eine Aufgabe.

Commands are stateless, short-lived objects used to perform a single unit of work within an application.

Das Mapping findet ebenfalls wieder in der startup-Funktion des Contexts durch den Befehl commandMap.mapEvent() statt.

Mit commandMap.mapEvent(HelloFlashEvent.BALL_CLICKED, CreateBallCommand, HelloFlashEvent ) wird auf das Event HelloFlashEvent.BALL_CLICKED reagiert. Als Reaktion wird der Command bzw. die Klasse CreateBallCommand ausgeführt. Außerdem wird automatisch das Event, das den Command ausgelöst hat, in das Command-Objekt injiziert (so könnte man dem Event Informationen mitgeben).

Wichtig in der Command-Klasse: Die Aufgaben werden einfach durch Überschreiben der Funktion execute() erledigt.

[as]
override public function execute():void
{
// Add a Ball to the view
// A Mediator will be created for it automatically
var ball:Ball = new Ball();
ball.x = Math.random() * 500;
ball.y = Math.random() * 375;
contextView.addChild(ball);
}
[/as]

Über contextView.addChild() wird hier beispielweise ein Objekt auf der Bühne hinzugefügt.

Links und Quellen

Link: www.robotlegs.org
Link: Robotlegs Beispiele
Link: TexFlex09 Robotlegs Slides
Link: Best Practices

[ad]

10 Gedanken zu „Einführung in das Robotlegs ActionScript-Framework“

  1. Hallo Florian,

    danke fuer den tollen Einstiegsartikel zu Robotlegs – meines wissens die erste deutsche Beschreibung des Frameworks.

    Ergaenzend moechte ich noch sagen, dass Robotlegs ueber die hier beschriebene Standard-Implementation des MVCS-Patterns hinaus viele Moeglichkeiten laesst, ganz andere Arbeitsweisen zu unterstuetzen. So lassen sich z.B. neben der Verwendung von Mediators auch direkt die Views selber mit Framework-Logik versehen, indem man sie in der ViewMap registriert. Auf diesem Wege laesst sich die von Robotlegs bereitgestellte Dependency Injection im View selber nutzen.

    Insgesamt ist Robotlegs neben einem vollstaendigen, aber im Aufgabengebiet bewusst begrenzten Application Framework vor Allem eine Art Baukasten fuer die Umsetzung eigener Workflows auf Basis des von Robotlegs bereitgestellten gemeinsamen Event-Busses und der Dependency Injection.

    Letztere kann uebrigens problemlos ausgetauscht werden: Wem mein mitgeliefertes SwiftSuspenders nicht gefaellt/ ausreicht, der kann SmartyPants (http://code.google.com/p/smartypants-ioc/) oder Spring (http://www.springactionscript.org/) benutzen, wobei es fuer Ersteres auch aktuelle Adapter gibt: http://github.com/darscan/robotlegs-adapters-SmartyPants

  2. Hi Till,
    vielen Dank für die ausführlichen Ergänzungen!
    Hatte gar nicht gesehen, dass da ja auch deutsche Wertarbeit in Robotlegs steckt ;)

    Ich hatte mir zuvor auch Parsley angeschaut. Da gibt es zwar eine gute Dokumentation, aber quasi keine Beispiele. Das macht den Einstieg dann eher frustrierend…

    Wie oben auch geschrieben habe, finde ich, dass man Robotlegs aufgrund der Beispiele und Präsentation recht leicht lernen kann. Habe gestern auch recht leicht etwas Bestehendes problemlos in das MVCS-Pattern von Robotlegs portieren können.

  3. Hey Flo,

    ja, die Beispiele fuer Robotlegs sind Gold wert! Und ich finde, dass auch die Dokumentation wirklich sehr gut ist – da leistet vor Allem Joel Hooks ganze Arbeit.

    Parsley ist aber auch ein gutes Framework und waere sicherlich meine Wahl, wenn es Robotlegs nicht gaebe.

  4. Hi,
    ist das wirklich richtig:

    "Mit eventMap.mapListener(eventDispatcher, HelloFlashEvent.BALL_CLICKED, onSomeBallClicked) wird ein Event an das Framework gesendet (nämlich an den zentralen eventDispatcher)."

    Dadurch registriere ich doch einen Listener auf Events, die vom Framework kommen, oder etwa nicht?

    Um Events zu versenden benötigt man doch "dispatch(event)".

    Vielleicht irre ich mich aber auch,
    Gruß Simon

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert