Guice 1.0 User's Guide和訳 その2

はじめに


前へ | 目次 | 次へ

Plain Old Factories - 昔ながらのファクトリーパターン

DI(Dependency Injection)が用いられるようになる前は、ファクトリーパターンが最も一般的に用いられていました。サービスのインターフェースに加えて、クライアントに提供するサービスの実装クラスと、テスト用のモック実装の両方を提供するようなファクトリーを一緒に作成していたと思います。シンプルにするために、ここではシングルトンなサービスを例として扱うことにします。

public class ServiceFactory {

  private ServiceFactory() {}
    
  private static Service instance = new ServiceImpl();

  public static Service getInstance() {
    return instance;
  }
  
  public static void setInstance(Service service) {
    instance = service;
  }
}

クライアントは通常、サービスが必要になる度に直接ファクトリーを使用します。

public class Client {

  public void go() {
    Service service = ServiceFactory.getInstance();
    service.go();
  }
}

このクライアントはとてもシンプルです。しかし、クライアントに対するユニットテストはモックサービスを用いて行う必要があり、テスト後はモックを使用するための設定の「後片付け」を行う必要があります。このサンプルではそれらは大した手間ではありませんが、クライアントやサービスが増える毎にユニットテストは大変になるはずです。もしユニットテスト後に「後片付け」を忘れてしまったならば、他のユニットテストは本来失敗するべきなのに成功してしまったり、成功するべきなのに失敗してしまったりするかもしれません。場合によっては、実行順序を変えるだけでテストが成功してしまったり失敗してしまったりする可能性もあります。

public void testClient() {
  Service previous = ServiceFactory.getInstance();
  try {
    final MockService mock = new MockService();
    ServiceFactory.setInstance(mock);
    Client client = new Client();
    client.go();
    assertTrue(mock.isGone());
  } finally {
    ServiceFactory.setInstance(previous);
  }
}

最後にもう一つ、ファクトリーパターンはシングルトン的なアプローチになりがちだということを留意点としてあげておく必要があります。もしgetInstance()メソッドがシングルトンでは無い複数のインスタンスを返すならば、setInstance()メソッドの実装はより複雑なものになるからです。