LoginSignup
10
9

More than 5 years have passed since last update.

Robotlegs2 とは

Last updated at Posted at 2014-03-12

Robotlegs2 (RL2) はドキュメント不足と初代 Robotlegs のドキュメントが混在するため学習しづらいと感じ、僕なりに導入部分をまとめてみようと思います。

注)この記事では Robotlegs2 のことを単に Robotlegs と書いていることがあります。

Robotlegs の動作環境

Robotlegs は以下の様な環境で動作します。

  • ActionScript3.0 を用いる
  • Adobe Flash
  • Flex
  • Adobe AIR
    • iOS/Android やデスクトップ環境で動く

Robotlegs の基本概念

Robotlegs は MVC フレームワークです。
特徴と言えるのは Dependency Injection (DI) を用いた制御の反転 (IoC) でしょう。

Dependency Injection (DI)

Robotlegs の DI のサンプルコードです。

Foo.as
public class Foo
{
    [Inject]
    public var bar:Bar;
}
Main.as
var injector:Injector = new Injector;

// map
injector.map(Bar).asSingleton();

// inject
var foo:Foo = new Foo;
injector.injectInto(foo);

trace(foo.bar is Bar); // => true

ここでは Bar クラスを「シングルトン」としてインジェクタに登録し、そのインジェクタで Bar クラスのインスタンスのインジェクトを行っています。
Bar のインスタンスはこのインジェクタを用いて他のインスタンスに「注入」されているのです。
インジェクトされる先のメンバは [Inject] と書かれたメンバの中で型(クラス・インターフェイス)が一致するものです。

IoC with DI

制御の反転 (IoC) とは、「タスクの実行のきっかけを作った人は、実行するタスクも知っている」という「作った人」から「タスク」への依存関係を切り離して「タスクは、何々をきっかけに実行する」と置き換える依存関係の反転を指す言葉です。
タスクにかぎらず色々な制御関係を反転することも IoC と言います。

Robotlegs の Injector の機能だけを利用した IoC で「ユーザ名が変更されたら表示する」という機能を実装してみましょう。

反転されていない書き方

User.as
public class User
{
    private var _printer:Printer = new Printer;
    private var _name:String;
    public function get name():String { return _name; }
    public function set name(value:String):void
    {
        _name = value;
        _printer.print("The user's name is " + name + ".");
    }
}
Main.as
var user:User = new User();
user.name = "Taro"; // => "The user's name is Taro."

一応表示されます。実装も短くてシンプルです。
しかし、これだと単なる User クラスが文字を表示する機能 Printer を知る必要がありますよね。
この依存関係はあまり良くないので、DI で切り離してみましょう。

制御の反転を行った書き方

User.as
public class User
{
    public const nameChanged:Signal = new Signal;
    private var _name:String;
    public function get name():String { return _name; }
    public function set name(value:String):void
    {
        _name = value;
        nameChanged.dispatch();
    }
}
PrintUsernameCommand.as
public class PrintUsernameCommand
{
    [Inject]
    public var user:User;

    private var _printer:Printer = new Printer;

    public function execute():void
    {
        _printer.print("The user's name is " + user.name + ".");
    }
}
Main.as
// configuration
var user:User = new User;
injector.map(User).toValue(user);

// when user.name changed then print the name
user.nameChanged.add(function():void
{
    // command instantiation
    var command:PrintUsernameCommand = new PrintUsernameCommand();
    injector.injectInto(command);

    // command execution
    command.execute();
});

user.name = "Taro"; // => "The user's name is Taro."

注) as3signals というライブラリを使っています http://qiita.com/tosik/items/2c1596abf3d43077fe6e

かなり複雑に見えるかもしれませんが、User クラスが Printer クラスを知らなくてよくなりました。
User と PrintUsernameCommand に分離し、User#name の変更時にその user インスタンスをインジェクとした PrintUsernameCommand の execute が実行されるようになっています。

ただ、依存分離が行えても Main 部分が雑だし記述量が多いのが面倒です。
そこで登場するのが Robotlegs です。(さっきのは Robotlegs の Injector しか使っていません)

Robotlegs による MVC の実例

先ほどの「ユーザ名が変更されたら表示する」を MVC で組み立てましょう。
今回は Printer を用いず TextField で名前を表示してみます。

Model

User.as
public class User
{
    public const nameChanged:Signal = new Signal;
    private var _name:String;
    public function get name():String { return _name; }
    public function set name(value:String):void
    {
        _name = value;
        nameChanged.dispatch();
    }
}

モデルは特に何も継承せず、普通のモデルクラスを書いてください。

View

UserView.as
public class UserView extends Sprite
{
    private var _nameTextField:TextField;
    public function UserView()
    {
        _nameTextField = new TextField;
        addChild(_nameTextField);
    }

    public function changeName(name:String):void
    {
        _nameTextField.text = name;
    }
}

ビューも Flash らしい普通の作り方で問題ありません。
一つ重要なのは UserView#changeName が public に実装されていることですね。

Mediator

UserViewMediator.as
public class UserViewMediator extends Mediator
{
    [Inject]
    public var view:UserView;
    [Inject]
    public var user:User;

    public override function initialize():void
    {
        user.nameChanged.add(changeView);
    }

    public override function destroy():void
    {
        user.nameChanged.remove(changeView);
    }

    public function changeView():void
    {
        view.changeName(user.name);
    }
}

これが User と UserView の仲介を行うメディエータです。
「ユーザの名前が変更された」というきっかけで「ビューにその名前を反映する」タスクを実行するだけのクラスです。
このクラスが Model-View の IoC において最も重要なものです。

Configuration

MainConfig.as
public class MainConfig implements IConfig
{
    [Inject]
    public var injector:IInjector;
    [Inject]
    public var mediatorMap:IMediatorMap;
    [Inject]
    public var contextView:ContextView;

    public function configure():void
    {
        injector.map(User).asSingleton();
        mediatorMap.map(UserView).toMeidator(UserViewMediator);

        contextView.addChild(new UserView);
    }
}

そしてこのクラスが、MVC の登場人物の依存関係のコンフィギュレーションを行うクラスです。
次のようなことを設定しています。

  • User はシングルトンである
  • UserView の対になるメディエータは UserViewMediator である

Application

Application.as
public class Application extends Sprite
{
    public function Apllication()
    {
        var context:Context = new Context()
            .install(MVCSBundle)
            .configure(MainConfig)
            .configure(ContextView(this))
        context.initialize();
    }
}

この Application クラスは Flash のエントリポイント用のルート Sprite です。
Robotlegs の初期化のお決まりの書き方となります。(拡張を導入するときはこの辺りに手を入れる)

以上が Robotlegs の基本的な使い方でした。

動作するサンプルコード

中くらいのサイズのサンプルコードとして使えそうなコードを github に上げています。合わせてご覧ください。
https://github.com/tosik/zenith

10
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9