日頃の業務でなんだかんだJavaを書きますが、良くわかっていない部分があったのでその解消。
Springフレームワークを使っていますが、他のクラスを利用する際にDIしますよね。
書き方としては、@Autowiredを利用する場合とコンストラクタを利用する場合があると思います。
皆さんはどちらでしょうか。
私が担当しているアプリでは後者のコンストラクタを利用する方が主流です。
せっかくなのでこの違いを整理してみました。
コンストラクタを利用する書き方
HogeValidatorクラスをDIする際こんな感じで書きます。
Main.Java
@Service
public class HogeServiceImpl implements HogeService {
// ① インターフェースのfinal宣言
private final HogeValidator hogeValidator;
// ② コンストラクタでのDI
public HogeService(HogeValidator hogeValidator) {
this.hogeValidator = hogeValidator;
}
@Override
void doHoge() {
hogeValidator.validate();
...
}
}
①ではinterfaceをfinalを使ってクラス変数として宣言します。
②のコンストラクタ部分では、HogeValidatorをDIします。
Autowiredを利用する際の書き方
Main.Java
@Service
public class HogeServiceImpl implements HogeService {
// Autowiredを用いたDI
@Autowired
private HogeValidator hogeValidator;
@Override
void doHoge() {
hogeValidator.validate();
...
}
}
メリット
コンストラクタ
- 他クラスとの依存関係が明白に
・一箇所に纏まる、見やすい - メンバ変数をfinalで宣言可能
・変数がイミュータブルになり、オブジェクトの安全性が向上する。
(final宣言ができる、ということ)
・スレッドセーフになる
・必ずメンバ変数がインスタンス化されてからコンストラクタが走る
- 依存関係が見つからない場合、コンパイルエラー
・早期にバグ修正できる
・逆に依存関係を環境変数によって切り替えができる
(本番では本番用の実装クラス、テストではテスト用のクラスを用いる、というような切り替え)
Autowired
- 1行でDIできるのでコードが完結
・楽で良いね
デメリット
コンストラクタ
- コードが冗長になる
・いちいち書くのは、、まあだるい
Autowired
- 他クラスとの依存関係が分かりにくくなる(可能性がある)
・バラバラに宣言できるので、誰かが変なところで依存関係を作るかもね、ということ - finalで変数宣言できない
・上の逆 - 依存関係が見つからない場合、実行時エラー
・実行しないとバグに気づけないのは怖いね
おわり
どちらがお好みでしょうか。
私はコンストラクタの方を好んでます。
コード書くのだるいですが、安全が確保されている方が好みです。
いずれにせよ、プロジェクト内で書き方が統一されているべきでしょう。
よかったら参考にしてみてください。