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

DI(Dependency Injection)戦略などと、それっぽい題名を付けているが大したことではない。一般的なクライアントアプリケーションに必要なリソース戦略と大して変わらない。DIの扱いに関してはいろいろなところで紹介されているが、明記されていないまでも、殆どがアプリケーションサーバ上で動作するサーバシステムでの使用を前提にしている。少なくともクライアントアプリケーションでDIコンテナを使うことについて書かれたものを見たことがない(需要も無いが)ので、自分で少しずつまとめることにした。

標題は"リッチクライアント"でも良いのだが、この言葉はちょっと範囲が広くなりすぎたので、最近は使わないようにしている。.NET WindowsForms2.0限定の話なんでスマートクライアントでいいかと。ただし、たまたま.NETを使用しているということであり、JavaのクライアントでツールキットにSwingやSWTを用いて、DIコンテナSeasar2やSpringを使用することを前提にしたとしても普遍的なことを書いているつもり。また、当然だが私見もある。

  • 1. DIの対象

小規模なものを除き、アプリケーションで使うユーザ定義の型全てをDIの対象にしようとは、ゆめゆめ思わないほうが良いと思う。当然だがアプリケーション内でnewするよりDIコンテナにお願いしてコンポーネントを生成、取得してくるほうが遥かにコストがかかるのだから。DIの対象とするにはコストを上回るメリットを享受できることが条件となるが、その場合対象になるのは以下が考えられる。

    • DIに向くと思われる
  • ユニットテストの対象となる型(アプリケーション内部で使用されるインタフェース、クラス)
  • 環境に依存した型(リモートコネクション、データコネクション)
  • プロパティが頻繁に変更される型(ウインドウの初期値、パーソナライズ情報)
  • ライフスパンの長い型

元々DIコンテナを使う大きなメリットの一つは、実装をすげ替えてテストを容易にすることなので、ユニットテストの対象となる型は一番にDIの対象になりうるだろう。実行時のプロパティが頻繁に変更される型は、設定からプロパティインジェクションの値を変えることでプログラムの再ビルド無しに振る舞いを変えられるメリットがあるので、これまたDIに向いている。あと、オブジェクトの特性というべきなのか、グローバルなオブジェクト等、インスタンスが生きている期間が長い型はDIの対象として考える。逆にDIの対象から外すことを考えるのはなんだろう。

    • DIに向かないと思われる
  • 大量のインスタンスを生成する型
  • DTOや層間を繋ぐライフスパンの短い(一時的な)型
  • 型階層の深い型(自動バインドを使う場合のみ)

DIコンテナは細かいインスタンス数の管理はしてくれないため、同じインスタンスを大量に生成する型はDIには向かないだろう。(個人的にはDIの対象にする型は、アスペクト以外、全て一つのインスタンスしか使わないことが明快で良いと思っている)DIによるインスタンスの生成は全てリフレクションによって行われるため、生成にコストがかかる。複雑なGUI、例えば多数のコントロールを貼ったFormクラスなども同様だが、アプリケーション内でインスタンスを一つに限定しても良い場合は、逆にDIに向く対象にもなりうる。また、メニューやツールバーなど、具体的なアクションと関連するGUIを動的に生成したい場合は代理となる、プロキシやディスクリプタ等を使ったりするが、これらに関してはDIの対象として柔軟にカスタマイズできるようにすると良いと思う。あと、型の階層が非常に深いものは、この後書く予定の依存性解決を自動で処理する場合コストが高く、やはりDIに向かない。ただし、依存性解決を明示的に(設定ファイル又はアノテーションで)行う場合はその限りではない。

ダウト(2006/04/28 11:33)

DIによるインスタンスの生成は全てリフレクションによって行われるため、生成にコストがかかる。

自分で書いておいてなんだが、JavaC#などで言えばこれはウソかな。両言語ともコンストラクタ情報が取得できれば、インスタンス生成の処理コストはnewと変わりないと。Javaのリフレクションは昔は遅かったが今は全然そんなことないし。