LoginSignup
1
1

More than 5 years have passed since last update.

Robotlegs2のMessageDispatcherを試してみる

Posted at

前回の続きです。

Robotlegs2はMessageDispatcherという機能があるのですが、探しても記事が無いので自分で試してみました。

MessageDispatcherとは?

MessageDispatcherは登録したエンドポイントへString型のメッセージを送る機能です。
Spring Frameworkにありますね。

使い方はEventに似ています。
Eventと違うのは、より不特定多数に同時に通知させるのに適しています。

実装サンプル

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

1.png

2.png

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

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

サンプルコードの説明

前回のサンプルコードに少し手を加えました。
変更を入れていないソースは説明を省略します。

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 
        {
            // おまじない

            // MessageDispatcherはシングルトンである
            injector.map(MessageDispatcher).asSingleton();

            // 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.impl.MessageDispatcherをシングルトン登録します。

injector.map(MessageDispatcher).asSingleton();

Message

MessageDispatcherからMessageを受け取れるようにクラスを作成します。

まずMessageの基礎クラスを作成します。
この基礎クラスはEventクラスみたいなものです。

Message.as
    /**
     * MessageDispatcherによってやり取りされるメッセージの基本クラスです。
     *
     * @author ogino
     */
    public class Message
    {

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

        /** メッセージタイプ */
        public var type:String;

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

        /**
         * コンストラクタです。
         *
         * @param type メッセージタイプ
         */
        public function Message(type:String)
        {
            this.type = type;
        }

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

        /**
         * オブジェクトのストリング表現を返します。
         *
         * @return オブジェクトのストリング表現
         */
        public function toString():String 
        {
            var qualifiedClassName:String = getQualifiedClassName(this);
            var className:String = qualifiedClassName.split("::")[1];
            return "[" + className + " (type = " + type + ")]";
        }
    }

次に以下のようにMessageを継承したクラスを作成します。

UserMessage.as
    /**
     * ユーザー関連のメッセージクラス
     * 
     * @author ogino
     */
    public class UserMessage extends Message 
    {

        //-----------------------------------------------------
        //クラス定数
        //-----------------------------------------------------         

        /** ユーザーデータ更新 */
        public static const UPDATE_USER_DATA:String = "updateUserData";

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

        /**
         * コンストラクタ
         * 
         * @param type String
         */
        public function UserMessage(type:String) 
        {
            super(type);
        }

    }

カスタムイベントクラスを作るようなイメージです。
これでMessageDispatcherを使用する準備が整いました。

Mediator

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

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

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

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

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

        [Inject]
        /** メッセージディスパッチャー */
        public var messageDispatcer:MessageDispatcher;      

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

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

            // メッセージディスパッチャーにUserMessage.UPDATE_USER_DATAを受け取ったらコールバックを実行するようにセット
            messageDispatcer.addMessageHandler(UserMessage.UPDATE_USER_DATA, UserMessageHandler);

        }

        /**
         * @inheritDoc
         */
        public override function destroy():void
        {
            // 登録したメソッドを削除
            view.removeEventListener(UserChangeEvent.USER_CHANGE, view_userChange);

            // メッセージディスパッチャーから受け取るメッセージを削除する。これでUserMessage.UPDATE_USER_DATAは受信できなくなる
            messageDispatcer.removeMessageHandler(UserMessage.UPDATE_USER_DATA, UserMessageHandler);
        }

        //-----------------------------------------------------
        //メッセージハンドラー
        //-----------------------------------------------------         

        /**
         * データ更新関連メッセージ メッセージハンドラー
         * 
         * @param   message
         */
        protected function UserMessageHandler(message:String):void 
        {
            switch (message) 
            {
                case UserMessage.UPDATE_USER_DATA: // このメッセージを受け取ったら画面更新する
                    view.nameChange(user.name);
                    break;
                default:
                    break;
            }

        }

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

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

MessageDispatcherをRobotlegs側から注入します。

[Inject]
public var messageDispatcer:MessageDispatcher;  

次にMessageDispatcherから特定のメッセージを受信した時に、コールバック関数を呼び出すように設定します。

messageDispatcer.addMessageHandler(UserMessage.UPDATE_USER_DATA, UserMessageHandler);

特定のメッセージから受信したコールバック関数を削除するには、以下の通りに記述します。

messageDispatcer.removeMessageHandler(UserMessage.UPDATE_USER_DATA, UserMessageHandler);

addEventListener、removeEventListenerと同じ使い方が出来ます。


コールバック関数は必ずString型の引数を一つ設定します。


protected function UserMessageHandler(message:String):void 
{
    switch (message) 
    {
        case UserMessage.UPDATE_USER_DATA: 
            view.nameChange(user.name);
            break;
        default:
            break;
    }

}

受け取ったメッセージごとにswitch文で処理を切り分けています。
このメソッドはUserMessage.UPDATE_USER_DATAを受信したら画面を更新しています。

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 messageDispatcer:MessageDispatcher;              

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

        /**
         * @inheritDoc
         */
        override public function execute():void 
        {
            user.name = "変更しました";

            // メッセージディスパッチャーにメッセージを通知
            messageDispatcer.dispatchMessage(UserMessage.UPDATE_USER_DATA);
        }

    }

MessageDispatcherをRobotlegs側から注入します。

[Inject]
public var messageDispatcer:MessageDispatcher;  

モデルを更新したらMessageDispatcherにMessageを通知します。

messageDispatcer.dispatchMessage(UserMessage.UPDATE_USER_DATA); 

これで、MessageDispatcherからUserViewMediator.UserMessageHandlerが呼ばれます。
UserViewMediator.UserMessageHandlerが呼ばれることにより、画面に表示されている文言が変更されます。

Model

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

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

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

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

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

        /**
         * @private
         */
        public function set name(value:String):void 
        {
            _name = value;
        }
    }

地味ですがMessageDispatcherでMediatorに更新を通知できるようになったので、EventDispatcherが必要なくなりました。


以上、サンプルコードの説明でした。

MessageDispatcherを利用するとより柔軟なDIコンテナの開発が出来そうです。
あくまでも使用例の一つなので他にもこういう使い方ができるよ、というのがあれば教えてください。

1
1
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
1
1