Robotlegs2を用いたFlash開発

  • 5
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

tosikさんが投稿した記事を参考に、Robotlges2を使用したサンプルアプリケーションを作成しました。
Robotlegs2のGitHubはコチラ

Robotlegs2とは

FlashでDIコンテナを実装するためのMVCS(Model-View-Controller-Service)フレームワークライブラリです。

Robotlegsの利点

DIコンテナのフレームワークはいくつかありますが、RobotlegsがDIコンテナを実装する上で必要最低限の機能をそろえており、他のライブラリに比べて一番学習コストが低いです。
DIコンテナをとりあえず試用したい、勉強したい場合にオススメです。

※新卒2人に簡単にRobotlegs2の概要と実装方法を教えた後、約2週間ほどでライブラリを使いこなしていました。

実装サンプル

「テスト表示」のテキストをクリックすると「変更しました」と表示する単純なアプリです。

クリック前.png

クリック後.png

今回のサンプルはここからダウンロードできます。

※サンプルはMVCモデルで実装しています。
FlashDevelopを使用しています。

サンプルコードの説明

Main

Main.as
    /**
     * フレームワーク Robotlegs2 サンプルプロジェクト
     * as3であればGraphics,Stage3D、Flexで使用可能
     * このプロジェクトはgraphicsで記載
     * 
     * @author ogino
     */
    public class Main extends Sprite 
    {

        //-----------------------------------------------------
        //コンポーネント
        //-----------------------------------------------------         

        /**
         * コンストラクタ
         */
        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        //-----------------------------------------------------
        //イベントハンドラー
        //-----------------------------------------------------         

        /**
         * 初期化
         * 
         * @param   e Event
         */
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            // Robotlegs2を起動するための設定
            // MVCSBundleをセット
            // コンフィグクラスをセット
            // 最後にコンテキストビューをセットし、初期化処理を実行

            var context:Context = new Context();
            // おまじない
            context.install(MVCSBundle);
            // コンフィグクラスをセット
            context.configure(MainConfig);
            // コンテキストビューとしてこの画面をセット
            context.configure(new ContextView(this));
            // Robotlegs2初期化
            context.initialize();
        }

    }

Robotlegs2を利用するにあたり、以下は必ず決まった書き方(おまじない)になります。

var context:Context = new Context();
context.install(MVCSBundle);
context.configure(MainConfig);
context.configure(new ContextView(this));
context.initialize();

MVCSを実現するだけなら、MVCSBundleをinstallすれば大丈夫です。

context.install(MVCSBundle);

ContextViewにドキュメントクラスを登録します。

context.configure(new ContextView(this));

ドキュメントクラスでなくても大丈夫ですが、変な動作するのも怖いのでinitialzeメソッドを呼び出すクラスを登録するのが無難です。


コンフィグクラスは連続で設定することも可能です。

context.configure(MainConfig).
     configure(ServiceConfig).
     configure(SocketServiceConfig);

最後にinitializeを呼び出します。これで初期化は終了です。

context.initialize();

Config

MainConfig.as
    /**
     * メイン画面のコンフィギュレーションを行うクラス
     * 
     * このクラスで以下の設定を実行しています。
     *  ・UserModel はシングルトンである
     *  ・UserView の対になるメディエータは UserViewMediator である
     *  ・メディエーターでUserChangeEvent.USER_CHANGEが呼ばれた場合、UserCommondを実行する
     * 
     * @author ogino
     */
    public class MainConfig implements IConfig 
    {

        //-----------------------------------------------------
        //コンポーネント
        //-----------------------------------------------------         

        /** 画面 */
        private var userView:UserView = new UserView();     

        //-----------------------------------------------------
        //プロパティ
        //-----------------------------------------------------         

        [Inject]
        /** インジェクター */
        public var injector:IInjector;

        [Inject]
        /** メディエーターマップ */
        public var mediatorMap:IMediatorMap;

        [Inject]
        /** イベントコマンドマップ */
        public var commandMap:IEventCommandMap;             

        [Inject]
        /** コンテキストビュー */
        public var contextView:ContextView;

        //-----------------------------------------------------
        //メソッド
        //-----------------------------------------------------         

        /**
         * コンフィギュレーション実行
         */
        public function configure():void 
        {
            // おまじない

            // UserModel はシングルトンである
            injector.map(UserModel, "modelName").asSingleton();
            injector.map(UserModel).asSingleton();

            // UserView の対になるメディエータは UserViewMediator である
            mediatorMap.map(UserView).toMediator(UserViewMediator);

            // メディエーターでUserChangeEvent.USER_CHANGEが呼ばれた場合、UserCommondを実行する
            commandMap.map(UserChangeEvent.USER_CHANGE).toCommand(UserCommand);

            // このような形で値を注入することも可能
            //var user:UserModel = new UserModel();
            //injector.map(UserModel, "modelName").toValue(user);           

            // おまじないを設定すると、下記の処理が出来る

            // 画面を切り替える このプロジェクトは一つしか画面がないので、このメソッドで初期化処理を実行
            contextView.view.addChild(userView);

            // DIコンテナからモデルを取得
            var m:UserModel = injector.getInstance(UserModel, "modelName");
            m.name = "テスト表示";
        }

    }

Configは必ずrobotlegs.bender.framework.api.IConfigをimplementsする必要があります。

public class MainConfig implements IConfig

Configクラスを実装する上で、以下のプロパティを設定する必要があります。

[Inject]
public var injector:IInjector;
[Inject]
public var mediatorMap:IMediatorMap;        
[Inject]
public var commandMap:IEventCommandMap; 

この3つはRobotlegs側が自動的に注入されるため、おまじないはありません。
※Injectタグをつけるプロパティは必ずpublicにしてください。


ドキュメント画面をConfigクラスで何か操作する場合、ContextViewをRobotlegsから注入する必要があります。

[Inject]
public var contextView:ContextView;

configureメソッド

configureメソッドでDIコンテナ化するクラスを登録します。


シングルトン登録は以下の書き方になります。

通常
injector.map(UserModel).asSingleton();
name指定
injector.map(UserModel, "modelName").asSingleton();

また、以下の方法でもシングルトンになります。

toValue
var user:UserModel = new UserModel();
injector.map(UserModel, "modelName").toValue(user); 

MediatorをViewに紐付けるには、以下の書き方になります。

mediatorMap.map(UserView).toMediator(UserViewMediator);

これでUserViewの対になるMediatorとして、UserViewMediatorがRobotlegsに登録されました。
※MediatorとViewは必ず1対1になる仕様です。


Commondを実行するイベントの登録は、以下の書き方になります。

commandMap.map(UserChangeEvent.USER_CHANGE).toCommand(UserCommand);

これでMediatorでUserChangeEvent.USER_CHANGEが呼ばれた場合、UserCommandクラスのメソッドが呼ばれるようになりました。


Mediator

UserViewMediator.as
    /**
     * ユーザー画面のメディエータクラス
     * UserModelとUserViewの仲介を行う
     * 「ユーザの名前が変更された」というきっかけで「ビューにその名前を反映する」タスクを実行するだけのクラス
     * 
     * @author ogino
     */
    public class UserViewMediator extends Mediator
    {

        //-----------------------------------------------------
        //コンポーネント
        //-----------------------------------------------------         

        [Inject]
        /** ユーザ画面 */
        public var view:UserView;

        //-----------------------------------------------------
        //プロパティ
        //-----------------------------------------------------         

        [Inject(name="modelName")]
        /** ユーザモデル */
        public var user:UserModel;

        //-----------------------------------------------------
        //オーバーライドしたメソッド
        //-----------------------------------------------------         

        /**
         * @inheritDoc
         */
        public override function initialize():void
        {
            // 名前が変更されたときに呼び出すメソッドをセット
            user.addEventListener(Event.CHANGE, changeView);
            view.addEventListener(UserChangeEvent.USER_CHANGE, view_userChange);
        }

        /**
         * @inheritDoc
         */
        public override function destroy():void
        {
            // 登録したメソッドを削除
            user.removeEventListener(Event.CHANGE, changeView);
        }

        //-----------------------------------------------------
        //イベントハンドラー
        //-----------------------------------------------------         

        /**
         * 画面更新
         * 
         * @param e Event
         */
        public function changeView(e:Event):void
        {
            view.nameChange(user.name);
        }

        /**
         * 画面変更通知イベントハンドラー
         * 
         * @param   e
         */
        private function view_userChange(e:UserChangeEvent):void 
        {
            // イベントをクローンする
            var newEvent:UserChangeEvent = UserChangeEvent(e.clone());
            // フレームワークに通知 このイベントに紐付けられたCommandクラスが呼ばれる
            eventDispatcher.dispatchEvent(newEvent);
        }       
    }

Mediatorは必ずrobotlegs.bender.bundles.mvcs.Medatorクラスを継承する必要があります。

public class UserViewMediator extends Mediator

Mediatorに紐付けられたView(この場合だとUserView)はMediator内でInjectタグで注入されます。

[Inject]
public var view:UserView;

Configクラスでシングルトン登録されたクラス(この場合はUserModelクラス)がある場合、Robotlegs側から注入されます

[Inject]
public var user:UserModel;

nameを指定すると、Configクラスでnameを指定することでRobotlegsから注入されます。
nameが違う場合、nameが無指定の場合は注入されません。

[Inject(name="modelName")]
public var user:UserModel;

MediatorクラスのeventDispatcherに、Configクラスで登録したイベントクラスをdispatchEventに渡すことで、Commandクラスを実行できます。

eventDispatcher.dispatchEvent(new UserChangeEvent(UserChangeEvent.USER_CHANGE));

※子画面からUserChangeEvent.USER_CHANGEをdispatchEventしてもCommandクラスは実行されないので注意


オーバーライドしたメソッドの説明


1.initializeメソッド
 Mediatorに紐付けられたViewがstageにaddChildされたタイミングでRobotlegs側から呼び出されます。


2.destroyメソッド
 Mediatorに紐付けられたViewがstageにremoveChildされたタイミングでRobotlegs側から呼び出されます。


Command

UserCommand.as
    /**
     * ユーザーに関するコマンド実行
     * このクラスはコンフィグで設定したイベントがメディエーターで呼ばれた場合、executeメソッドがフレームワーク側から実行される
     * 他のクラスから、コマンドを直接実行させるのは控えること
     * 
     * @author ogino
     */
    public class UserCommand extends Command
    {

        //-----------------------------------------------------
        //プロパティ
        //-----------------------------------------------------         

        [Inject]
        /** イベント コマンドを実行したいイベントクラスをpublicで必ず記載すること */
        public var event:UserChangeEvent;       

        [Inject(name="modelName")]
        /** ユーザモデル */
        public var user:UserModel;      

        [Inject]
        /** コンテキストビュー */
        public var contextView:ContextView;     

        //-----------------------------------------------------
        //オーバーライドしたメソッド
        //-----------------------------------------------------         

        /**
         * @inheritDoc
         */
        override public function execute():void 
        {
            var view:UserView = new UserView();

            view.y = 20;
            user.name = "変更しました";
            // 画面を追加表示 コマンドクラスで画面遷移を実施するのがよさそう
            contextView.view.addChild(view);
        }

    }

RobotlegsにおいてCommandクラスはControllerです。

注意

Commandクラスは使い捨てです。
Commandに紐付けられたイベントクラスがMediatorから呼ばれるたびに、Robotlegs内でnewされています。


Commandは必ずrobotlegs.bender.bundles.mvcs.Commandクラスを継承する必要があります。

public class UserCommand extends Command

Commandクラスでは、Configクラスで紐付けられたイベントクラス(この場合はUserChangeEventクラス)をInjectタグで指定すると、Robotlegs側から注入されます。

[Inject]
public var event:UserChangeEvent;

MVCSの場合、CommandクラスからServiceを呼び出します。


[Inject]
public var service:SocketService;

override public function execute():void 
{       
   service.send();
}


オーバーライドしたメソッドの説明


1.executeメソッド

 Commandに紐付けられたイベントクラスがMediator.eventDispatcher.dispatchEventを実行することで、Robotlegs側から呼び出されます。
 必ずoverrideしてください!


Model、View、Event

Model、View、Eventは通常通りの実装です。

UserModel.as
    /**
     * ユーザー名のモデルクラス
     * 
     * @author ogino
     */
    public class UserModel extends EventDispatcher
    {

        //-----------------------------------------------------
        //プロパティ
        //-----------------------------------------------------     

        //---------------
        //name
        //---------------   

        /**
         * @private
         */
        private var _name:String;

        /**
         * ユーザー名
         */
        public function get name():String { return _name; }

        /**
         * @private
         */
        public function set name(value:String):void 
        {
            _name = value;
            // 変更を通知
            dispatchEvent(new Event(Event.CHANGE));
        }
    }
UserView.as
    /**
     * ユーザー情報表示画面
     * 
     * @author ogino
     */
    public class UserView extends Sprite 
    {

        //-----------------------------------------------------
        //コンポーネント
        //-----------------------------------------------------         

        /** ユーザー名表示領域 */
        private var nameTextField:TextField;

        //-----------------------------------------------------
        //コンストラクタ
        //-----------------------------------------------------         

        /**
         * コンストラクタ
         */
        public function UserView() 
        {
            super();

            nameTextField = new TextField();
            nameTextField.addEventListener(MouseEvent.CLICK, nameTextFieldClickHandler);
            addChild(nameTextField);
        }

        //-----------------------------------------------------
        //メソッド
        //-----------------------------------------------------         

        /**
         * 名前変更
         * 
         * @param   name
         */
        public function nameChange(name:String):void 
        {
            nameTextField.text = name;
        }

        //-----------------------------------------------------
        //イベントハンドラー
        //-----------------------------------------------------         

        /**
         * 名前テキストをクリックしたときのイベントハンドラー
         * 
         * @param   e
         */
        private function nameTextFieldClickHandler(e:MouseEvent):void 
        {
            var e:MouseEvent = new MouseEvent(MouseEvent.CLICK);
            dispatchEvent(e);

            // メディエーターに更新イベントを通知
            dispatchEvent(new UserChangeEvent(UserChangeEvent.USER_CHANGE));
        }
UserChangeEvent.as
    /**
     * ユーザーがデーターを変更した時のイベントハンドラー
     * 
     * @author ogino
     */
    public class UserChangeEvent extends Event 
    {

        //-----------------------------------------------------
        //イベント定数
        //-----------------------------------------------------         

        /** ユーザー変更 */
        public static const USER_CHANGE:String = "userChange";

        //-----------------------------------------------------
        //コンストラクタ
        //-----------------------------------------------------         

        /**
         * コンストラクタ
         * 
         * @param   type
         * @param   bubbles
         * @param   cancelable
         */
        public function UserChangeEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) 
        { 
            super(type, bubbles, cancelable);
        } 

        //-----------------------------------------------------
        //オーバーライドしたメソッド
        //-----------------------------------------------------         

        /**
         * @inheritDoc
         */
        override public function clone():Event 
        {
            var e:UserChangeEvent = new UserChangeEvent(type, bubbles, cancelable);
            return e;
        }

    }

以上、Robotlegs2 の実装したサンプルコードの説明になります。