PureMVC for AS3 ver2.0.4 フレームワーク解説 ver0.9.2 更新履歴 日付 バージョン 更新内容 2009/05/20 0.9 新規作成 2009/06/22 0.9.1 Mediatorの動的作成を追加 2009/12/21 0.9.2 一部公開用に修正 フレームワーク導入の効果 ► MVCを分離し、それぞれのレイヤーの役割を明確化。 導入するだけで既にMVCモデルの基本構造は実現可能 ► 処理パターンに従うことで、実装方法が標準化 プログラマのスキル及び創意工夫による品質のばらつきが解消され、全 体の品質が向上。 可読性向上 ► プロジェクトの生産性向上及び開発工数の削減 PureMVC ► 訴求点 フリー、オープンソース MVCモデルに準拠 シンプルで軽い AS2、AS3, Java, C#、iPhone(Objective C)、Ruby向けもある Cairngormの評判が悪いので… フレームワーク ► Cairngorm http://opensource.adobe.com/wiki/display/cairngorm/ ► easyMVC http://projects.simb.net/easyMVC ► Guasax http://www.guasax.com/guasax/web/en/index.php ► Mate http://mate.asfusion.com/ ► Model-Glue http://www.model-glue.com/flex.cfm ► Parsley http://www.spicefactory.org/parsley/ ► Penne http://www.flexpasta.com/index.php/category/penne-framework/ ► Pure MVC http://puremvc.org/ ► Swiz http://code.google.com/p/swizframework/ ► Flight http://www.flightxd.com/flightframework ► yui-frameworks http://akabana.sandbox.seasar.org/ja/products/yui/index.html Cairngorm ► 特徴 Adobeが開発しているFlexのフレームワーク Eventをトリガーにビジネスロジックをハンドリング ► 利点 View、コントローラ、ビジネスLogicの完全分離。 ビジネスLogicがイベントとセットで完全に独立しており、他の層に対して 疎結合。 ビジネスLogicを再利用する必要がある要件との親和性が高い。 ► 欠点 学習コストが高い。 1機能単位あたりの必要クラス数が多く、保守性上昇の代わりに生産性 が低下する。 PureMVC ► 特徴 必要最低限で軽い Eventではなく、オブザーバーパターンのNotificationを使って複数コン ポーネント間をハンドリング シンプルなので拡張やメンテナンスがしやすい ► 利点 学習コストが低い 対応している言語が多いので一度覚えれば、他でも使える Cairngormで多くできたEventが減らせる ► 欠点 柔軟性がある反面あいまいな部分もある。⇒ローカルルールが必要 大規模開発にはカスタマイズが必要 ハンドリングが文字列依存 PureMVCのクラス(org.puremvc.as3) puremvc View Observer IObserver View Facade IMediator IController IFacade Mediator Controller INotifier ICommand IModel Notifier Model IProxy Proxy SimpleCommand INotification MacroCommand Notification ≪implements≫ ≪extends≫ ValueObject Responder ServiceDelegate 概念図 出典:puremvc.org 概念図その2 出典:flex_framework @ ウィキ Facade ► ► ► 以下、赤字はローカルルールです。 フレームワークの中心 シングルトン Facadeを介してModel、 View、 Controllerを参照 Proxy、Command、Mediatorを登録する(register) Proxy、Command、Mediatorを削除する(remove) Proxy、Mediatorを参照する(retrieve) ► MVCのコアクラスを隠蔽 コアクラス ►MVCの各層を管理するコアアクター。 ►さらに上位の管理クラスであるFacadeで管理されている。 View ► ► MediatorとObserverの管理 シングルトン Controller ► ► Commandの管理と実行 シングルト Model ► ► Proxyの管理 シングルトン フレームワークのコアクラスですが、これらのクラスはFaçadeを介してやりとりされるの で直接使用することはありません。 【View層】 View ComponentとMediator ► View Component UI部分。通常MXMLで記述される。 Viewは、その他のレイヤーを参照しない ► ► Mediatorを介してPureMVCにアクセスする。 ViewからMediatorはイベントでハンドリング。 View内で簡潔するロジックはViewに記述する。 ► Mediator ViewHelper、Viewとフレームワークの橋渡し役 Viewを内部に保持していて、Viewを制御する ► ユーザイベントをNotificationに紐付け Viewからディスパッチされたイベントをハンドリングし、 Notificationを送る ► NotificationをViewに反映 FrameworkからNotificationを受け取り、Viewを制御 Model(Proxy)の参照を行う。 listNotificationInterests ► Mediatorが扱うNotificationリスト handleNotificationl ► Notificationが渡されたときの処理 View ComponentのSub Componentは各々のMediatorを作成せず、できるだ け親のMediatorでハンドルする。 【 Controller層】 Command ► Command Notificationを受け処理を実行するBusinessロジック部 Commandクラスを継承し、executeメソッドを実装する。 必要なパラメータは、 Notificationから取り出す(getBody) ► SimpleCommand 1つのコマンド ► MacroCommand 複数コマンド実行 ► addSubCommandでコマンドを登録。 前のコマンドの結果を待つわけではない。 ► SimpleCommandをループでexecuteしているだけ。 【Model層】 DataObject とProxy ► DataObject PureMVCでは、ProxyクラスがDataObjectを保有する。 ► Proxy Domainロジックを実装するためのクラス ModelとModelを出し入れするためのコントロールを備えている。 ► CairngormではModel層はデータの入れ物だっただけ データのまとまりごとに作成。 ► LoginInfoProxy, SharedObjectProxy, UploadFileProxy サーバサイドの処理はDelegateに依頼する。 Proxyから発行されるNotification ► ProxyからNotificationが発行される ⇒MediatorがNotificationを受け取り、Viewに結果を反映する。 Notification例: ► DataObjectを更新したらNotificationを投げる (成功失敗がない単純な値やリストの更新カレントアイテムの変更、リスト、フラグの更新など) ⇒Viewの更新、フィードバック、ステートの変更など ► 処理が成功したらNotificationを投げる。 ⇒処理成功のフィードバック、画面遷移、ステートの変更など ► 処理が失敗したらNotificationを投げる。 ⇒エラーのフィードバックなど ※同一Modelを複数箇所から参照している可能性があるので変更時には注意する。 【Service層】 Service Delegate ► ► ► ► ► MVCSのS サーバサイドのロジックとのやりとりを記述する Proxyの依頼を受けて処理を実行 resopnderで結果をProxyに返す resultHandler 通信成功 ► 結果:成功 ► 結果:失敗 ► faultHandler 通信失敗 ObserverとNotifier ► ► ► PureMVCでは、 Observer-Notificationパターンを使用。 Event-EventDispatcherの換わり MVCフレームワークとその他を疎結合にする ►EventとNotification Event ►EventはFlash Platform依存 ►バブリングの機構も親子階層の中でしか使えない。 ►厳密に型を定義しないといけないので面倒 Notification ►NotificationはPublish/Subscribeパターン ►複数のObserverが同じNotificationを受け取れる。 ►オプション値のBodyはObject型。型を気にしないでいいので楽チン。 ►Event依存でないので他の言語やプラットフォームとの親和性があがる。 Notification ► Notifierによって送信される。 Mediator, Proxy, (SimpleCommand, MacroCommand, Façade) ※Notificationの発行は、Mediator、Proxyからのみとします。 ► Notification(name:String, body:Object = null, type:String = null) name Notificationを識別する名前 ► アプリケーション内でユニーク ► 定数クラスで管理⇒PureMVCConst.as ► body ► ValueObjectを乗せる入れ物 例:LoginUserParam.as(userId、password) type Notificationのタイプを区別したいときに使用する。 ► 同じような処理や機能で、commandを複数作る必要もないとき。 ► 例:sendNotification(PureMvcConst.CALL_SQLCONNECTION, file, SQLConnectionCommand.OPEN); Notification名について ► 定数クラスで管理⇒PureMVCConst.as コマンドの呼び出し通知 ► 主にMediatorが発行する ► callを付ける 例: public static const CALL_LOGIN:String = "callLogin“ ► Commandと紐付けが必要 例: facade.registerCommand(PureMVCConst.CALL_LOGIN, LoginCommand); 単純な値やリストの更新通知 ► 主にProxyが発行する ► update/changeを付ける 例: public static const CHANGE_CURRENT_ITEM:String = “changeCurrentItem“ 処理成功/失敗通知(非同期処理) 主にProxyが発行する ► 成功:successを付ける ► 例: public static const SUCCESS_LOGIN:String = "successLogin"; ► 失敗:failureを付ける 例: public static const FAILURE_LOGIN:String = "failureLogin"; BodyとTypeの使い方 ► コマンドの呼び出し通知時 body ► リクエストパラメータ(ValueObject) type ► ► 処理タイプ、IDなど 単純な値やリストの更新通知時 body ► なし type ► ► なし 処理成功通知時 body ► なし type ► ► なし 処理成功/失敗通知 body ► エラーオブジェクト type ► なし Mediatorの登録について ► MediatorManager createMediator() ► Viewのインスタンス化完了時に呼び出し、対応するMediatorを生成する。 お作法どおりだと インスタンスへの参照を渡さないとい インスタンスへの参照を渡さないとい けない⇒レイアウトを変更し難い けない⇒レイアウトを変更し難い // View:LoginPanelとLoginPanelMediatorのひも付け facade.registerMediator(new LoginPanelMediator(app.loginPanel)); facade.registerMediator(new ResultPanelMediator(app.resultPanel)); 変更後 例)Main.as <?xml version="1.0" encoding="utf-8"?> <mx:Canvas xmlns:mx=http://www.adobe.com/2006/mxml creationComplete="init()" > <mx:Script> <![CDATA[ import practice.extended.MediatorManager; インスタンス化完了時に インスタンス化完了時に private function init():void インスタンスを渡す インスタンスを渡す { MediatorManager.createMainMediator(this); } ]]> </mx:Script> </mx:Canvas> 例)MediatorManager.as public static function createMainMediator(targetViewComponent:Object):void { var mainMediator:MainMediator = new MainMediator(targetViewComponent); ApplicationFacade.getInstance().registerMediator(mainMediator); } Mediatorの動的な生成 ► Mediatorは、基本的にはシングルインスタンス mediatorの識別IDであるmediatorNameはconst ► 同一クラスから複数のView componentを生成する場合、対応するMediatorも複数 生成する必要があります。 mediatorの識別IDを動的に付与 例)ItemComponentMediator.as public class ItemComponentMediator extends Mediator { 接頭辞をconstで指定 接頭辞をconstで指定 // Mediatorの名称の接頭辞 public static const NAME_PREFIX:String = 'ItemComponentMediator'; /** * コンストラクタ * @param mediatorName コンストラクタで、mediatorName コンストラクタで、mediatorName * @param viewComponent (要ユニーク)を動的に付与。 (要ユニーク)を動的に付与。 * */ public function ItemComponentMediator(mediatorName:String, viewComponent:Object) { super(mediatorName, viewComponent);} } Mediatorの動的な生成 例) AddItemCommand.as override public function execute(notification:INotification):void { var uid:String = UIDUtil.createUID(); // ユニークID DBのuidなど。 var itemVO:ItemVO = new ItemVO(uid); 要求時にCommandを呼び出し 要求時にCommandを呼び出し // Proxyにアイテムを追加する _itemProxy.addItem(itemVO); } /** * アイテムを追加する。 * @param itemVO アイテム * itemVOからview componentとそのmediatorを動的に生成し、紐付ける * */ public function addItem(itemVO:ItemVO):void { // modelの追加 _itemList.addItem(itemVO); Proxyで、Model/View/Mediatorを一緒に Proxyで、Model/View/Mediatorを一緒に 管理する。 管理する。 // Mediatorの追加 var mediatorName:String = ItemComponentMediator.NAME_PREFIX + itemVO.itemId; var itemComponent:ItemComponent = new ItemComponent(); itemComponent.name = mediatorName; itemComponent.itemVO = itemVO; var itemComponentMediator:ItemComponentMediator = new ItemComponentMediator(mediatorName, itemComponent); facade.registerMediator(itemComponentMediator); // viewの追加 例) ItemProxy.as var parentComponentMediator:ParentComponentMediator = ParentComponentMediator.getInstance(); parentComponentMediator.addItemComponent(itemComponent); } Proxyの登録について ► getInstanceメソッド Proxyを取得する。なければ生成し、登録する お作法どおりだと // Model:Proxyを登録 StartUpCommandで StartUpCommandで 登録 登録 facade.registerProxy(new LoginProxy()); 変更点 例) ItemProxy.as /** * Proxyインスタンスを取得する。 * @return * */ public static function getInstance():ItemProxy { if (!ApplicationFacade.getInstance().hasProxy(PROXY_NAME)) { ApplicationFacade.getInstance().registerProxy(new ItemProxy()); } return ApplicationFacade.getInstance().retrieveProxy(PROXY_NAME) as ItemProxy; } (お詫び) この記述だとProxy同士で相互参照している場合、無限ループになってしまうので注意。 パッケージ構成の例 TIPS ViewStackなどでは、Viewは要求があったタイミングでインスタンス化されま す。このタイミングではNotificationのハンドルが間に合わない場合がありま す。 ► Notificationの相互参照で無限ループになりえるので注意。 ► 参考 ► Cairngorm http://opensource.adobe.com/wiki/display/cairngorm/Cairngorm/ ► PureMVC http://puremvc.org/ ► flex_framework @ ウィキ http://www39.atwiki.jp/flex_framework/
© Copyright 2024 Paperzz