.NETにおけるDIの今後

ObjectBuilderのDI機構を利用するための方法は大きく2通りである。

  1. オブジェクトを取得する前にそのオブジェクトのDependency情報をObjectBuilderに設定する。
  2. オブジェクトを取得する際にクラス内の属性(Attribute)をObjectBuilderに読み取らせてDependencyをインジェクトさせる。

前者の方法は世間一般に見られる設計ファイルなどを利用してDIする方法である。(ObjectBuilderには設定ファイルを読み込む機能はない) 後者はソースコードの中に属性を定義する方法である。

.NET開発、.NET開発者はそもそもインタフェースベースであるとか設定情報の外だしであるとかといった文化がないと言われている。従ってDependency情報を設定ファイルに外だしするとなると開発者がついてこれない可能性もあるし、メンテナンス性も落ちるし、ソースコードをトレースしづらいという問題も残る。
結果としてDIという思想が浸透しないということも納得がいく。

.NETにおいてDIを浸透させるためにはソースコード内に全て設計情報を閉じ込めてやるアプローチの方が良いのではないかと思う。

今までやっていたことを少しだけ変えてやるだけで開発者はDIであるとかコンテナであるとかを意識せず、そのようにコードを書くことが当たり前という世界を作ってしまうことが近道なのではないかと思う。

今までのコード

private IService service;
public Finder() {
    service = new Stage1ServiceImpl();
}
public DataSet Find(String name) {
    int number;
    if () {
        number = …
    } else if () {
        number = …
    } else if () {
        number = …
    } else {
        number = …
    }
    return service.FindByNameNumber(name, number);
}

//利用者側のコード
Finder finder = new Finder();
DataSet ds = finder.Find(name);

今後のコード

private IService service;
[Dependency(Name="Stage1", CreateType=typeof(Stage1ServiceImpl)]
public Finder(IService _service) {
    service = _service;
}
public DataSet Find(String name) {
    int number;
    if () {
        number = …
    } else if () {
        number = …
    } else if () {
        number = …
    } else {
        number = …
    }
    return service.FindByNameNumber(name, number);
}

//利用者側のコード
Finder finder = container.GetObject();
DataSet ds = finder.Find(name);

たったこれだけの変更でFinderのテストはStage1ServiceImplに依存しない形で実行できるし、Stage1ServiceImplからStage2ServiceImplへの変更も属性を変えるだけである。またもしStage1ServiceImplのインスタンスをシングルトンにしたければ、属性に追加してやれば良い。インスタンスの管理もする必要がなくなる。Stage1ServiceImplのクラス名が変更になった場合、VSのリファクタリング機能を使えば、属性のtypeof(XXX)の部分も変更になる。従って今までの設定ファイル外だしのデメリットであるソースコードと設定ファイルの同期問題も考える必要がなくなる。

少しの変更でほんの少しのメリットが生まれる。最初はこれで良いと思う。

こんなんじゃまだ駄目だろうか?