スマートクライアントのDI戦略(その2)

登録するコンポーネント間の依存性を宣言的、又は自動的に解決するのがDIコンテナの特徴的な機能だ。しかし、依存性の解決にも当然ながら処理コストがかかるので、クライアントアプリケーションではその辺を考慮して依存性解決の方法を決めなくてはならないだろう。

    • 自動バインド

自動バインドの強度(DIコンテナによって、全て自動で行う、一部自動で行う、自動では行わない等)にもよるが、指定された型に対して、
+ 生成時の適切なコンストラクタの選択と実行
+ 生成後に実行する初期化メソッドの実行
+ 生成後のプロパティとフィールドの設定
これらをリフレクションによる型情報と、設定情報により「できるだけ」自動的に実施する機能である。非常に強力な機能だが、自動的に行う範囲を広げれば広げるほどに、型情報を探索する範囲も広がるため、型の階層とプロパティの数に比例して処理コストが上がり、以前に書いたように意図しないバインドや、すぐには必要の無いコンポーネントの生成が発生する可能性が高くなるため、使用には注意が必要である。制約の多いスマートクライアントは、手動バインドを使用したほうが好ましいだろう。

    • 手動バインド

設定ファイルやカスタム属性への記述等を利用して、コンポーネント間の依存性を全て手動で解決する方法。依存性を明示的に記述していくので面倒だが、型情報の探索は必要最小限しか行われないので処理の負荷は低い。スマートクライアントではできるだけこちらを使うべきだろう。

DIコンテナによっては自動で依存性を解決する機能を更に発展させた、コンポーネントの自動登録を行う機能を持つものがある。Javaの場合であればファイルシステムやjarファイル中の型をパターンに沿って探索し、合致した型のインスタンスを自動生成するが、.NETの場合であればモジュール、アセンブリなどを対象にして探索するであろう。この機能はコンポーネントの探索を行うためにコンポーネントを明示的に指定するよりは処理が増える、それでも上述した依存性の自動バインドに比べれば大した負荷ではない。従ってスマートクライアントでは、この方法により記述の手間を省くとともに、設定ファイル又はカスタム属性による手動バインドにより、必要最小限なコンポーネントを生成するようにするのが良いだろう。

両方ともDIを行うためのメタデータを記述する手段として用意されている。

    • 設定ファイル

DIのメタデータの記述の基本になるのは設定ファイルである。コンポーネントの型、インスタンススコープ、自動バインドの強度、注入するプロパティ、初期化メソッドなどを指定する。データの構造を記述できることからXMLで書かれることが殆どであり、Javaの場合は外部のテキストファイルとして作成し、それを読み込むのが普通だ。また、設定ファイルに全てのコンポーネントの記述を行う場合等はファイルの記述量が多くなるため、ファイルの分割機能を持っている。
.NETの場合はプロジェクト中のリソースをアセンブリに埋め込むことができるため(マニフェストリソース)、複数に分けた設定ファイルのうち、比較的静的なコンポーネントの記述をアセンブリに埋め込み、実行する際に変更する可能性のある動的な記述は外部のファイルにすることができる。スマートクライアントの場合、配布するファイルは少ないに越したことが無いので設定ファイルは積極的にアセンブリに埋め込むのが良い。

アノテーション(カスタム属性)による記述は、主に設定ファイルを補うために使用する。補うため、と書いたのはこれだけでは役に立たないからである。
アノテーション(カスタム属性)によるメタデータの記述は、型そのもの、又は型の持つメソッド、プロパティやフィールドに対して行うため、その型の情報をDIコンテナが認識していなければメタデータも認識できないのである。従ってアノテーション(カスタム属性)によるDIは、前述したDIコンテナによる依存性の解決時やコンポーネントの自動生成、自動登録と共に使用する。また、アノテーション(カスタム属性)によるメタデータはソースファイルに直接記述するため、他の開発者と共有している型に対して設定することはできない。
共有している型に対してメタデータを設定するには、その型を派生させて使用することが必要になる。スマートクライアントでは、前述したコンポーネントの自動生成を使用して設定ファイルの記述を省きたい場合は、カスタム属性による記述を積極的に利用することになるだろう。