研究ノート@EffectiveJava
記事の内容は、Joshua Bloch-Effective Java(3rd)-2018.chmという本からのものです。
第2章
オブジェクトの作成と登録解除
項目5は、ハードワイヤードリソースよりも依存性注入を優先します
ハードワイヤリングリソースより
も依存性注入を優先する多くのクラスは、1つ以上の基礎となるリソースに依存しています。
静的ツールクラス:
// Inappropriate use of static utility - inflexible & untestable!
public class SpellChecker {
private static final Lexicon dictionary = ...;
private SpellChecker() {} // Noninstantiable
public static boolean isValid(String word) { ... }
public static List<String> suggestions(String typo) { ... }
}
シングルトン:
// Inappropriate use of singleton - inflexible & untestable!
public class SpellChecker {
private final Lexicon dictionary = ...;
private SpellChecker(...) {}
public static INSTANCE = new SpellChecker(...);
public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}
これらの方法はどちらも、1つの辞書だけを使用する価値があると想定しているため、満足のいくものではありません。
辞書フィールドを非最終に設定し、既存のスペルチェッカーにメソッドを追加して辞書を変更することで、SpellCheckerが複数の辞書をサポートするようにすることができますが、これは厄介でエラーが発生しやすく、同時設定では実行できません。静的ユーティリティクラスとシングルトンは、動作が基盤となるリソースによってパラメータ化されているクラスには不適切です
必要なのは、クラスの複数のインスタンス(この例ではSpellChecker)をサポートできるようにすることです。各インスタンスは、クライアントが必要とするリソース(この例では辞書)を使用します。
この要件を満たす簡単なパターンは、新しいインスタンスを作成するときにコンストラクターにリソースを渡すことです。これは依存性注入の形式です。辞書はスペルチェッカーの依存関係であり、辞書の作成時にスペルチェッカーに注入されます。
// Dependency injection provides flexibility and testability
public class SpellChecker {
private final Lexicon dictionary;
public SpellChecker(Lexicon dictionary) {
this.dictionary = Objects.requireNonNull(dictionary);
}
public boolean isValid(String word) { ... }
public List<String> suggestions(String typo) { ... }
}
依存性注入は、コンストラクター、静的ファクトリメソッド、およびジェネレーターにも適用されます
パターンの便利な変形は、リソースファクトリをコンストラクタに渡すことです。ファクトリは、型のインスタンスを作成するために繰り返し呼び出すことができるオブジェクトです。これらのファクトリは、ファクトリメソッドパターン[Gamma95]を具体化しています。Java 8で導入されたSupplierインターフェースは、ファクトリを表すのに非常に適しています。サプライヤの入力へのアプローチでは、通常、制限付きワイルドカードタイプ(アイテム31)を使用して、ファクトリのタイプパラメータを制約し、クライアントが指定されたタイプのファクトリのサブタイプを渡して作成できるようにする必要があります。たとえば、以下は、顧客が提供する工場を使用してモザイクを作成し、各タイルを作成する方法です。
Mosaic create(Supplier<? extends Tile> tileFactory) { ... }
つまり、シングルトンまたは静的ツールクラスを使用して、1つ以上の基になるリソースに依存するクラスを実装しないでください。これらのリソースの動作はクラスの動作に影響を与え、クラスがこれらのリソースを直接作成しないようにします。代わりに、リソースまたはそれらを作成したファクトリをコンストラクター(または静的ファクトリまたはジェネレーター)に渡します。依存性注入と呼ばれるこの方法により、クラスの柔軟性、再利用性、およびテスト性が大幅に向上します。
要約すると、シングルトンまたは静的ユーティリティクラスを使用して、動作がクラスの動作に影響を与える1つ以上の基になるリソースに依存するクラスを実装したり、クラスにこれらのリソースを直接作成させたりしないでください。代わりに、リソース、またはそれらを作成するためのファクトリをコンストラクター(または静的ファクトリまたはビルダー)に渡します。依存性注入として知られるこの手法は、クラスの柔軟性、再利用性、およびテスト性を大幅に向上させます。