BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース アプリケーションをDependency Injectionフレームワークから分離する

アプリケーションをDependency Injectionフレームワークから分離する

ブックマーク

原文(投稿日:2010/01/20)へのリンク

Dependency Injection(依存性の注入)は、ずっと受け入れられるようになってきた。そして近年、SOA,TDDそして多くの他の要因が、人気を増してきていることを含んで、多くの要因に後押しされて、Dependency Injectionは、利用しやすい手法になってきた。こうしたことに伴って、Dependency Injectionフレームワークの使用が増えてきており、そのハイライトが最近、 Java EE 6にも使われたことである。例を使って、Bob Martin氏は、自分のアプリケーションコードとお好みのDependency Injectionフレームワークとを、疎結合化する手法の適用を勧めている。

彼の Dependency Injection Inversion に関する投稿で、[Bobおじさん]こと、Martin氏は、メッセージを次の簡単な声明でズバリ言っている:

... 私は、[Dependency Injection]フレームワークのコードが、私のアプリケーションの至る所を汚して欲しくありません。私は、フレームワークをうまく疎結合のままにしたい、そして私のコードの本体にべったりして欲しくないんです。

この点を説明するために、Martin氏は、以下の依存性をそのコンストラクタで、定義しているBillingServiceクラスの生成を中心に展開する例をあげている:

public class BillingService {
	...
	BillingService(CreditCardProcessor processor, TransactionLog transactionLog) {
		this.processor = processor;
		this.transactionLog = transactionLog;
	}
	...
}

彼は、最初、BillingService クラスのインスタンスを生成するのに、 Guice (Googleの Dependency Injection フレームワーク)を使うコード片を紹介している:

public static void main(String[] args) {
	Injector injector = Guice.createInjector(new BillingModule());
	BillingService billingService = injector.getInstance(BillingService.class);
	billingService.processCharge(2034, "Bob");
}

(Guiceを使って)ここで実際に起きていることの詳細のいくつかを検討した後に、Martin氏は、以下の事実を問題視している、すなわち、BillingServiceのインスタンスを生成するために、今やあなたは、Guiceにinjectorを明示的に頼まなければならない、立場にいる、という事実である。BillingServiceを必要としているコードは、もはやBillingServiceが依存しているものには、密に依存していない(いいこと)、しかし、今や、Guiceに密に依存している。

あなたは、単に1つのまずい事を別のものと交換しただけなのか?Martinは、そうだ、と言っている:

Dependency Injectionは、Dependency Inversion(依存性の逆転)の特別なケースに過ぎません。私は、Dependency Inversionは、非常に重要なので、私は、Guiceへの依存を逆転させたいと思います!私は、たくさんの具体的なGuiceへの依存が私のコード中の至る所に存在して欲しくありません。

後で、彼は、手製のFactoryのようなオブジェクトをどのように使って、アプリケーションのDIフレームワークへの依存性を制御し、そして減らせるかを示している:

public static void main(String[] args) {
	Injector injector = Guice.createInjector(new BillingModule());
	BillingService.factory = new BillingServiceFactory(injector);
}
...
// 私のシステムの奥深い所
BillingService billingService = BillingService.factory.make();
billingService.processCharge(2034, "Bob");

なぜこの手法が役に立つかについて、詳細に説明しながら、Martin氏は、このように言っている:

今や、Guiceの全ては、よく理解できる1箇所にあるので、私は、この手法が好きです。私のアプリケーションの至る所には、Guiceは、いません。Guiceっぽいファクトリによって、Guiceが私のアプリケーションの至る所を汚染するのを防いでいます。更にいいのは、私が、Guiceを他のDIフレームワークと交換したいと思ったら、私は、どのクラスを、どのように変える必要があるのかを正確に知っています。そう、私は、Guiceと私のアプリケーションとが結合しないように、維持しています。

説明中で面白い点は、使われた全ての例で、BillingService自身は、Dependency Injectionの原則に固執していることである;BillingServiceが依存するもの(CreditCardProcessorTransactionLog)は、どのような実装が使われているかについての知識が、BillingServiceの外に置かれている。この説明のために、この記事の終りに、TransactionLogCreditCardProcessorから、簡単な手製の"テストダブル(代役)"を使う、BillingServiceのJUnitテストを示して、アプリケーションが実行時に依存性を注入するのに、どの方法を選ぼうが、このテストは、ちゃんと走る、と言っている。

(Martin氏のテストダブルやそれらを"手作りする"ことをはっきりと、選択することに関連した傍注として、Gary Bernhardt氏が、 大変面白い記事 を投稿し、Javaや他の静的に型づけする言語では、このような決定は非常に賢いかもしれないが、Pythonのような動的言語では、必ずしもそうでない、と強調している。)

さて、あなたは、Dependency Injectionを使うか?DIフレームワークを使うか? もしそうなら、あるいは、またもしそうでないとしても、これらのことを、どれだけあなたは、理解されただろうか?

この記事に星をつける

おすすめ度
スタイル

BT