はじめに
Javaによるオブジェクト指向開発を行うときに必ず出てくるのがDI(Dependency Injection)です。
DIは依存性の注入と訳され、オブジェクトの依存関係を外部から注入することで、コードの結合度を下げ、テストしやすく、保守性の高い設計を可能にします。
DIにはいくつか種類があってそれぞれ特徴があります。
今回はDIについて説明します。
1. コンストラクタインジェクション
コンストラクタを通じて依存性を注入します。
依存するオブジェクトはコンストラクタの引数として渡されるため、オブジェクトが生成されるときに必要な依存性が全て設定されます。
特徴:
- 依存性が不変であるため、オブジェクトが一度作成されるとその依存性は変更されません。
- コンストラクタが複雑になる可能性がありますが、依存性が全て揃っていることが保証されます。
public class Service {
private final Repository repository;
public Service(Repository repository) {
this.repository = repository;
}
// ビジネスロジック
}
2. セッターインジェクション
セッターメソッドを使用して依存性を注入します。
オブジェクトが生成された後、セッターメソッドを呼び出すことで依存性を設定します。
特徴
- 依存性がオプションであり、オブジェクトが作成された後に依存性を設定できるため、柔軟性があります。
- 必要な依存性が設定されていない可能性があるため、セッターメソッドを使う際には注意が必要です。
public class Service {
private Repository repository;
public void setRepository(Repository repository) {
this.repository = repository;
}
// ビジネスロジック
}
3. フィールドインジェクション
フィールドに直接依存性を注入します。
通常、Javaの依存性注入フレームワーク(例えば、Spring)ではアノテーションを使用して依存性を注入します。
特徴
- コードが簡潔になりますが、依存性がクラスの状態として直接注入されるため、テストが難しくなる可能性があります。
- 依存性が非公開フィールドとして扱われるため、カプセル化の原則が破られることがあります。
public class Service {
@Autowired
private Repository repository;
// ビジネスロジック
}
4. インターフェースインジェクション
インターフェースを通じて依存性を注入します。
依存するクラスはインターフェースを実装し、そのインターフェースを通じて依存性を注入されます。
特徴
- より明示的な依存性注入が可能になりますが、インターフェースの設計が必要です。
- 他のDIの種類に比べて少し複雑な実装になります。
public interface RepositoryAware {
void setRepository(Repository repository);
}
public class Service implements RepositoryAware {
private Repository repository;
@Override
public void setRepository(Repository repository) {
this.repository = repository;
}
// ビジネスロジック
}
まとめ
- コンストラクタインジェクションは依存性が必須である場合に推奨されます。
- セッターインジェクションは依存性がオプションである場合に適しています。
- フィールドインジェクションはコードの簡潔さを重視しますが、テスト性の問題がある可能性があります。
- インターフェースインジェクションは依存性の明示的な管理が必要な場合に使用されます。
それぞれのDIの種類には利点と欠点があり、具体的な要件やプロジェクトの状況に応じて適切な方法を選ぶことが重要です。