AOContainer

ソースコード / ライセンス / ドキュメント / ASDoc

AOContainer ドキュメント

AOContainerは「Dependency Injection」(DI)を行う軽量コンテナです。 

DIとは、インターフェースと実装を分離して、オブジェクトを外部から生成し設定する仕組みで、代表的なDIコンテナには「Seasar(S2Container)」「Spring Framework」「PicoContainer?」などがあります。AOContainerは、これらのコンテナを参考に開発されました。

このドキュメントは書きかけです。ASDocも併せてご覧下さい。

オブジェクトの定義

AOContainer は、コンテナに登録されている「オブジェクト定義」に従って、オブジェクトの生成を行います。オブジェクト定義には、「どのクラスのインスタンスを生成するか」「どのような依存関係があるか」「その依存関係をどのようにDIするか」といった情報が含まれます。

一般的に、オブジェクト定義はXMLを用いて作成します。例えば次のようになります。

<objects>
    <object name='obj' class='Object'/>
    <object name='str' class='String'/>
</objects>

これで、「obj」と「str」という名前で、「Object」と「String」クラスのオブジェクト定義をひとつずつ作ったことになります。詳しくはAOContainerの設定をご覧下さい。

XMLを用いる他に、AOContainer#registerClassメソッドを用いてクラスを直接登録する方法と、AOContainer#registerObjectメソッドを用いてオブジェクトを直接登録する方法もあります。

オブジェクトの親子関係

オブジェクト定義は親子関係を形成することが出来ます。XMLの場合、object要素を入れ子にすることで形成出来ます。次のようになります。

<objects>
    <object name='obj' class='Object'>
        <object name='str' class='String'/>
    </object>
</objects>

これで、「str」は「obj」の「子」、「obj」は「str」の「親」になります。

このような親子関係は、インジェクションで重要になってきます。AOContainerでは、オブジェクトをインジェクトする際に、「親子関係を見て距離が最も近いオブジェクト」をインジェクトするからです。

これによって、オブジェクト名やクラスが重複していても、距離さえ変えておけば、意図するオブジェクトを簡単にインジェクトできるようになります。つまり、依存関係のあるオブジェクトは近くに定義することによって、インジェクションのミスを減らすことが出来ます。

オブジェクトの取得

AOContainer#getObject メソッドに、オブジェクト名又はクラスを指定すると、それに当てはまるオブジェクトを取得することが出来ます。クラスを指定した場合は、そのクラスのサブクラスのオブジェクトも取得できます。オブジェクトがひとつに定まらない場合はDuplicateError?がスローされます。

AOContainer#getObjectsメソッドを使用すると、当てはまるオブジェクト全てを配列形式で取得することが出来ます。

インジェクション

AOContainerでは、次のタイプのDependency Injectionをサポートします。

コンストラクタインジェクション

コンストラクタの引数に対してDIを行うものです。設定はarg要素によって行います。

プロパティインジェクション

セッターメソッド又はパブリックなプロパティに対してDIを行うものです。設定はproperty要素によって行います。

例えば「hoge」という名前のプロパティに対してDIを行う場合、次のいずれかを宣言しておけばDIが行えます。

// setメソッド
public function set hoge(value:*):void
// セッターメソッド
public function setHoge(value:*):void
// パブリックなプロパティ
public var hoge:*;

メソッドインジェクション

メソッドに対してDIを行うものです。メソッドを呼び出し、引数に任意の値をDIすることが出来ます。設定はmethod要素によって行います。

自動インジェクション

毎回DIの設定を書くのは面倒です。そこで、AOContainerでは「Convention over Configuration」の考えに従って、自動インジェクション機構が用意されています。

プロパティインジェクションにあるような、セッターメソッド又はパブリックなプロパティを宣言すると、そのプロパティの型か、そのプロパティの型と名前の両方に当てはまるオブジェクトを、特に設定をしなくても自動でインジェクトします。

自動インジェクションもオブジェクトの親子関係を考慮して行われるので、インジェクトさせたいオブジェクトを近くに定義しておけば間違いが少なくなります。

オブジェクトの配備

AOContainerでは、オブジェクトの配備方法に次のものをサポートします。

シングルトン

GoFの「Singleton」パターンと同様に、AOContainer#getObjectや、DIを何度行っても、常に同じインスタンスが返されます。

プロトタイプ

AOContainer#getObjectや、DIを行うたびに新しいインスタンスが生成されます。

セミプロとタイプ

プロトタイプと同様に新しいインスタンスが生成されますが、親オブジェクトの配備中の間は同じインスタンスが返されます。

AOContainerの設定

AOContainerの設定はXMLによる記述をサポートしています。ActionScript?3では、E4Xが採用されているので、スクリプト内に直接XMLを書くことが出来ます。

var config:XML =
 <objects>
     <object name='obj' class='Object'/>
 </objects>;

このようにして書いた設定を、AOContainerFactory#createメソッドに渡すことによって、その設定がなされたAOContainerを取得することが出来ます。

var container:AOContainer = AOContainerFactory.create(config);

以下の項目では、XMLによって設定可能な設定の一覧を示します。

objects要素

必須です。設定のルートとなる要素です。

子として記述可能な要素は次の通りです。

設定可能な属性はありません。

object要素

任意です。オブジェクトを定義するための要素です。

子として記述可能な要素は次の通りです。

object要素を子要素として書いた場合、そこで親子関係が作られます。各インジェクションでは、この親子関係を考慮して、最も近い距離にあるオブジェクトがインジェクトされます。

設定可能な属性は次の通りです。

name属性

任意です。オブジェクトの名前を設定するための属性です。

ここで設定された名前を利用して、コンテナからオブジェクトを取得したり、インジェクトするオブジェクトを指定したり出来ます。

class属性

必須です。オブジェクトのクラスの完全修飾名を設定するための属性です。

ここで指定されたクラスのインスタンスが生成されます。name属性と同様に、ここで設定されたクラスを利用して、コンテナからオブジェクトを取得することも出来ます。

deployment属性

任意です。オブジェクトの配備方法を設定するための属性です。

設定可能な値は次の通りです。

デフォルト値は「singleton」です。

injection属性

任意です。自動インジェクションを行うかどうかを設定するための属性です。

設定可能な値は次の通りです。

  • 「auto」自動インジェクションを行います。
  • 「manual」自動インジェクションを行いません。

デフォルト値は「auto」です。

arg要素

任意です。object要素の子要素として書いた場合にはコンストラクタインジェクションを行うための要素です。method要素の子要素として書いた場合にはメソッドインジェクションの引数を設定するための要素です。

いずれの場合も、記述した順番に従って、コンストラクタやメソッドに引数として値が渡されます。

子として記述可能な要素はありません。

ボディにはインジェクトされる値の記述で指定された値が記述できます。

設定可能な属性は次の通りです。

isArray属性

任意です。複数のオブジェクトをインジェクトするかどうかを設定するための属性です。

trueを設定すると、該当する全てのオブジェクトが配列としてインジェクトされます。

property要素

任意です。プロパティインジェクションを行うための要素です。

子として記述可能な要素はありません。

ボディにはインジェクトされる値の記述で指定された値が記述できます。

設定可能な属性は次の通りです。

name属性

必須です。インジェクト先のプロパティの名前を設定するための属性です。

ここで指定された名前のプロパティに対して、ボディで記述された値がインジェクトされます。

isArray属性

任意です。複数のオブジェクトをインジェクトするかどうかを設定するための属性です。

trueを設定すると、該当する全てのオブジェクトが配列としてインジェクトされます。

method要素

任意です。メソッドインジェクションを行うための要素です。

子として記述可能な要素は次の通りです。

子として記述されたarg要素を引数としてメソッドを呼び出します。arg要素がひとつも書かれない場合は、引数なしでメソッドを呼び出します。

設定可能な属性は次の通りです。

name属性

必須です。インジェクト先のメソッドの名前を設定するための属性です。

ここで指定されたメソッドが呼び出されます。

finalize要素

任意です。解体時のインジェクションを指定するための要素です。

子として記述可能な要素は次の通りです。

ここで子として記述された各インジェクションが解体時に行われるようになります。現時点では、シングルトンのみが対応しています。

設定可能な属性はありません。

インジェクトされる値の記述

インジェクトされる値には、次のものを書くことが出来ます。

オブジェクト名

obj

のように、単純に識別子を書くと、それをオブジェクト名とみなして、該当するオブジェクトをインジェクトします。

オブジェクト名はオブジェクト要素name属性で記述されたものです。

ActionScript?リテラル

"hello"

1024

のように、ActionScript?で認識可能なリテラルを書くと、その値をそのままインジェクトします。

記述可能なリテラルは次の通りです。

  • 文字列:「"str"」など
  • 数値:「1」「0xff」「3.14」など
  • 論理値:「true」「false」
  • null