OpenLaszloアドバンスド・テクニック
連載:Flexのクライアントサイドをオープンソースで制覇する
(3)

Flexのフレームワーク、Cairngormのアーキテクチャ

ダイヤモンドコンピューターサービス
SI技術部 技術推進グループ
吉田 靖宏
2006/8/22
前回(Flexのフレームワーク、Cairngormを使ってみよう)では、FlexのインストールやEclipse上で開発する準備、Cairngorm Framework(ケアンゴーム)に付属しているログインサンプルを使ってフレームワークの動作確認を行った。今回は、ログインサンプルを構成するクラスを見ながら、Cairngorm Frameworkのアーキテクチャについて解説していく

アーキテクチャの全体像

 まず、初めにCairngorm Frameworkのアーキテクチャの全体像を説明します。下の図を見てください。これは、Cairngorm Frameworkの処理の流れを示した大まかな図です。以下、図の番号に沿って流れを説明していきます。

図 1 Cairngorm Frameworkのアーキテクチャ

- PR -
  1. View(MXML)は、“ボタンがクリックされた”“データグリッドの選択行が変わった”などのイベントの発生に基づき、ViewHelperのメソッドを呼び出す
  2. ViewHelperは、ValueObjectを生成し画面の入力値をセットする
  3. ViewHelperは、Cairngorm Frameworkのクラス(EventBroadcasterクラス)を用いて、イベントを発生させる。このイベントは、1.のイベントと違い開発者自身が定義する(ex : ログインイベントなど)
  4. Cairngorm Frameworkでは、すべてのイベントはControllerに通知されることになっているため、Controllerに発生したイベントが通知される
  5. Controllerは、通知されたイベントに対応するCommandを取得し、そのCommandを実行する
  6. Commandでは、サーバサイドのサービスにアクセスするためにBusinessDelegateのメソッドを呼び出す
  7. BusinessDelegateは、Cairngorm Frameworkのクラス(ServiceLocatorクラス)を用いて、サービスが定義されているServicesからサービスをルックアップする
  8. BusinessDelegateは、取得したサービスのメソッド(ビジネスロジック)を呼び出す
  9. サーバサイドのサービス呼び出しの結果がCommandまで戻ってくるので、Commandは呼び出しに成功した場合と失敗した場合のハンドリングを行い、画面に表示させたいデータをModelLocatorに設定する
  10. View(MXML)は、ModelLocatorを参照して画面の表示を行う

 以上が、Cairngorm Frameworkの処理の大まかな流れとなります。J2EEパターンを知っている方であれば、もう何となく分かってしまった方もいるのではないでしょうか。また、Strutsを使ったことがあれば、「ControllerはActionServlet、ValueObjectはActionForm、CommandはActionにそれぞれ対応してそうだ」と思った方もいるのではないでしょうか。知らない用語ばかりで何をいっているのか分からなかったという方、後述の解説をご参照ください。

View(MXML)

 では、最初にView(MXML)から見ていくことにしましょう。下のリストは、ログインサンプルのViewであるLogin.mxmlです。LoginViewHelperをインスタンス化し、LoginボタンがクリックされたときにLoginViewHelperのloginUserメソッドを呼び出しているのが分かります。

 また、<mx:Form>〜</mx:Form>の下にある<mx:Text>タグでは、textプロパティにModelLocatorのstatusMessageプロパティを設定しています(ModelLocatorについては、この後に説明します)。

 statusMessageには、ログインに失敗したときに表示されるメッセージがセットされており、ログイン失敗時にはそのメッセージが画面に表示されます。ModelLocatorは、Login.mxmlとは違うパッケージに存在するので<mx:Script>タグ内でインポートを行っています。

 「じゃあ、ログインに成功したときに表示される日付はどこで出しているの?」という疑問が浮かんでくると思いますが、ログインに成功した場合には画面を遷移させてログインの日付を表示しています。

 ログインサンプルのIndex.mxmlを見てもらえば分かりますが、ViewStackコンテナによりLogin.mxmlとラベルだけを持ったVBoxコンテナの2つが保持されており、ログインに成功した場合にはラベルだけを持ったVBoxコンテナの方に画面を切り替えています。このラベルにログイン日付が設定され、画面に表示されるというわけです。

リスト 1 Login.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.macromedia.com/2003/mxml"
          xmlns:view="org.nevis.cairngorm.samples.login.view.*"
          title="Login"
          horizontalAlign="center">

    <!-- ViewHelperのインスタンス化 -->
    <view:LoginViewHelper id="loginViewHelper" />

    <mx:Script>
    <![CDATA[  
        <!-- ModelLocatorのインポート -->
        import org.nevis.cairngorm.samples.login.model.ModelLocator;

    ]]>
    </mx:Script>

    <mx:Form id="loginForm">

        <mx:FormItem label="Username: ">
            <mx:TextInput id="username" />
        </mx:FormItem>

        <mx:FormItem label="Password: ">
            <mx:TextInput id="password" />
        </mx:FormItem>

    </mx:Form>

    <!-- ModelLocatorを使用して画面にデータを表示 -->
    <mx:Text text="{ ModelLocator.statusMessage }" marginLeft="40" 
width="400" height="30" />

    <mx:ControlBar>
        <!-- ボタンがクリックされたらViewHelperのメソッドを
呼び出す -->
        <mx:Button label="Login" click="loginViewHelper.
loginUser()" />
    </mx:ControlBar>
    
</mx:Panel>

ViewHelper

 次にViewHelperを見てみましょう。ViewHelperは、J2EEパターンの1つでViewから画面に関するロジックを分離させて、保守性を高めるパターンです。MXMLでは、<mx:Script>タグ内にAction Scriptを記述することができるため、ついここに画面回りのロジックをいろいろと書いてしまいがちですが、そうするとViewとロジックが密接に関係して保守性が下がってしまいます。

 このパターンを適用することで、ViewであるMXMLには画面回りのロジックが入り込まず、MXMLをViewの役割に専念させることができます。実際、先ほど見てもらったLogin.mxmlには、Action Scriptのロジックは全く入っていません。代わりに、画面回りのロジックはこのViewHelperで実装することになります。

 下のリストは、ログインサンプルのViewHelperであるLoginViewHelperです。Loginボタンをクリックしたときに呼ばれるloginUserメソッドでは、ValueObjectを生成しその中に入力値であるユーザー名とパスワードをセットしています。

 ここで画面からの入力値を取得する際に、view.XXX(XXXはMXML ID名)という記述でMXMLコンポーネントにアクセスしています。これは、個々のViewHelperはCairngorm FrameworkのViewHelperを継承して作成するため、各ViewHelperからはview.XXXという方法で画面のコンポーネントにアクセスできるようになっているからです。

 その後、Cairngorm Frameworkで用意されているEventBroadcasterクラスのbroadcastEventメソッドを用いてログインイベントを発生させています。このイベントは、Flexで用意されているイベントではなく開発者自身が定義します。

 定義といってもControllerクラスに、イベント名を表す文字列をクラス変数として宣言するだけです(Controllerについては、この後に説明します)。broadcastEventメソッドの第1引数には発生させたいイベント名を、第2引数にはValueObjectのインスタンスを渡します。

リスト 2 LoginViewHelper.as

class org.nevis.cairngorm.samples.login.view.LoginViewHelper extends ViewHelper {

    public function loginUser() {
        // ValueObjectを生成し、画面の入力値をセット
        // view.XXX(XXXはMXML ID)でMXMLコンポーネントにアクセスが可能
        var loginVO : LoginVO = new LoginVO();
        loginVO.username = view.username.text;
        loginVO.password = view.password.text;

        // ログインイベントを発生させる
        EventBroadcaster.getInstance().broadcastEvent( DemoControl.EVENT_LOGIN,
        loginVO );
    }
}

ValueObject

 ValueObjectは、J2EEパターンの1つで画面の入力値などをまとめて保持しておくクラスです。J2EEパターンでは、TransferObjectといわれます。もともとは、EJBのリモートメソッド呼び出しの回数を減らして、パフォーマンスの低下を防ぐのが目的のパターンです。

 下のリストは、先ほどのLoginViewHelperの中で生成されたLoginVOです。ログイン画面の項目であるユーザー名とパスワードのほかに、ログインした日付を保持するプロパティを持っています。toStringメソッドでは、Javaと同じようにオブジェクトの文字列表現を返していますが、実装は必須ではありません。

 ValueObjectで特徴的なことは、ObjectクラスのregisterClassメソッドを用いてAction ScriptのクラスとJavaのクラスのマッピングを行っていることです。ここでマッピングを行っておくことによって、クライアントサイドのAction Scriptのクラスが自動的にサーバサイドのJavaのクラスに変換されます。この仕組みのおかげで、クライアントサイドとサーバサイドのデータのやりとりをオブジェクト単位で行うことができます。詳細については、次回のサンプルアプリケーション作成で解説します。

 個々のValueObjectは、Cairngorm FrameworkのValueObjectインターフェイスを実装して作成します。ValueObjectインターフェイスは、何もメソッドが定義されていないインターフェイスです。そのため、このインターフェイスを実装しても何らかのメソッドの実装が強制されることはありません。

マーカーインターフェイス

1つもメソッドが定義されていない空のインターフェイスは、「マーカーインターフェイス」と呼ばれることがあります。これは、あるクラスにその「型」を実装しているという印(マーカー)を付けるために使われます。Java言語では、SerializableインターフェイスやCloneableインターフェイスがこのマーカーインターフェイスに該当します。

リスト 3 LoginVO.as

class org.nevis.cairngorm.samples.login.vo.LoginVO implements ValueObject {

    // このオブジェクトの文字列表現を返す(実装は必須ではない)
    public function toString() : String {
        var s : String = "LoginVO[username=";
        s += username;
        s += ", password=";
        s += password;
        s += ", loginDate=";
        s += loginDate;
        s += " ]";
        return s;
    }

    // Action ScriptのクラスとJavaのクラスのマッピング
    public static var registered:Boolean =
        Object.registerClass( "org.nevis.cairngorm.samples.login.vo.LoginVO",
        LoginVO );

    // ユーザー名
    public var username : String;
    // パスワード
    public var password : String;
    // ログイン日付
    public var loginDate : Date;
}

  1/2

 INDEX

連載:Flexのクライアントサイドをオープンソースで制覇する(3)
 Flexのフレームワーク、Cairngormのアーキテクチャ
Page1 アーキテクチャの全体像
View(MXML)/ViewHelper/ValueObject
  Page2 Controller
Command/ModelLocator/BusinessDelegate/Services




HTML5 + UX フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日 月間
ソリューションFLASH