CSSを使用したFlex2版DIコンテナ

CSSを設定ファイルに使用した、Flex2用のDIコンテナを作成しました。

ライブラリとソース

http://code.google.com/p/asphalt2/のFeatured Downloadsから、asphalt2container_v0_01_00.zipをダウンロードしてください。
これ自体がeclipseプロジェクトになっています。またbinフォルダにswcファイルが、srcフォルダにソースが入っています。
ライブラリだけ使う場合は、asphalt2container.swcをプロジェクトにいれパスを通すと、使用可能になります。


SVNでチェックアウトしたい場合は、
http://asphalt2.googlecode.com/svn/trunk/asphalt2container-project/asphalt2container/
をチェックアウトしてください。
また
http://asphalt2.googlecode.com/svn/trunk/asphalt2container-project/asphalt2container-test/
がテストプロジェクトになっていますので、こちらももっていくといいと思います。

ClassReference

Flex2CSSには「ClassReference」という組み込み関数があります。
例えば

Panel{
 border-skin:ClassReference("panelskin.Border");
}

としておくと、panelskin.Borderというクラスを使用して、Panelの枠を描画できます。


この関数をCSS内で使用すると、
・型の存在チェックをしてくれる
・宣言した型は、swf内に読みこんでくれる
という機能を使うことが出来ます。


元々画面のスタイルを定義するための機能ですが、この2つの特徴はDIコンテナを作成するのにはとても便利なため、CSSを定義ファイルに用いることにしました。

機能

機能としては
CSSから指定のインスタンスの取得
インスタンスへのプロパティインジェクション
・スコープ管理(シングルトンとプロトタイプ)
の3つがあります。

BeanFactory

インスタンスを取り出すためのインターフェースとして、「BeanFactory」というインターフェースを定義しています。
Spring先生ありがとうございます。

/**
 * Bean生成Factoryインターフェース
 * @auther c9katayama
 */
public interface BeanFactory
{
	/**
	 * beanNameを使用してbeanを検索し、beanインスタンスを返します。
	 */
	function getBean(beanName:String):Object;
	/**
	 * Classを使用してbeanを検索し、beanインスタンスを返します。
	 */
	function getBeanByType(clazz:Class):Object;
}

また、この実装クラスとして、「CSSBeanFactory」というクラスを実装してあります。
実際に使用するのは、このクラスです。

使用方法

はじめに、インターフェースを実装クラスを作成します。

//インターフェース定義
public interface Hoge{
  function printName():void;
}

//実装定義
public class HogeImpl implements Hoge{
  private var name:String;
  public function set name(value:String):void{
    _name = value;
  }
 public function printName():void{
     trace(_name);
  }
}


次に、CSSを使用して設定ファイルを記述します。(例えばbeans.cssというような名前で保存します)

Hoge{
  bean-type:ClassReference("bean.impl.HogeImpl");
  bean-scope:singleton;
 name:"HOGE";
}
.hogehoge{
  bean-type:ClassReference("bean.impl.HogeImpl");
  bean-scope:prototype;
 name:"HOGE_HOGE";
}


設定ファイルを、アプリケーションに読み込ませます。



最後に、BeanFactoryからBeanを取得します。

 var factory:BeanFactory = CSSBeanFactory.getInstance();

 var hoge:Hoge = factory.getBeanByType(Hoge) as Hoge;
 hoge.printName();// "HOGE" と出力される

 var hogehoge:Hoge = factory.getBean("hogehoge") as Hoge;
 hogehoge.printName();// "HOGE_HOGE" と出力される

読み込ませるCSSを変える事で、取得するインスタンスを変えることが出来ます。
またCSSをコンパイルしてswfにしておけば、動的にロードすることも(多分)できます。

設定ファイル

CSSのタイプセレクタ(上記だとHoge{}のセレクタ)は、主にBeanFactory#getBeanByType()を使用するときに使います。
BeanFactory#getBean("Hoge")でもgetBeanByType(Hoge)と同様に値を取得できますが、ByTypeの方が型チェックが入るのでいいとおもいます。
クラスセレクタは、BeanFactory#getBean()でbeanを取得する際に使用します。


セレクタで宣言が必須なのが、「bean-type」のプロパティです。
このプロパティでは、実際にインスタンス化する型を定義します。


スコープ宣言を行うのが、「bean-scope」のプロパティです。
「singleton」と「prototype」が宣言できます。
宣言のない場合、singletonスコープが適用されます。


それ以外は、インスタンスに設定するプロパティとみなします。文字列、数値、配列がサポートされています。
また、「${}」の記述を使用すると、ほかのbeanをインジェクトすることができます。
例えば

HogeService{
	bean-type:ClassReference("test.asphalt2.factory.impl.HogeServiceImpl");
	barService:"${BarService}";
}
BarService{
	bean-type:ClassReference("test.asphalt2.factory.impl.BarServiceImpl");
	bar:100;
}

とすると、HogeServiceのbarServiceプロパティに、BarServiceで取得できるbeanがインジェクトされます。

今後

${}を導入したので、ognl式をある程度評価できるようになったら便利かなと思ったり、${fn:today()}とかあっても便利かなと思いました。
あとはプロパティインジェクト時の型変換でしょうか。String->Dateぐらいは変換できるようにしたいと思います。
あと、Embed関数でがんばればいいと思っているので、いまのところ非同期的なプロパティ取得(たとえばcsvファイルのロードとか)は考えていません。