Javaにおける「疎結合」はどこまで許されるか

「疎結合(loose coupling)」は、設計においてしばしば正義のように語られます。
しかし、疎結合であることは常に正しいのでしょうか?

本記事では、「疎結合であること」それ自体が設計上の目的ではなく、目的を実現するための“手段”であるという前提に立ち、
Javaで疎結合を設計する際の限界、そしてレビュー時に注目すべき判断基準を整理します。

疎結合とはなにか? ――定義の再確認

設計上の「疎結合」とは、モジュールやクラス間の依存度を下げ、変更の影響範囲を狭める設計方針です。

密結合との対比
  • 密結合(tight coupling):あるモジュールの変更が他に直結する構造
  • 疎結合(loose coupling):依存の方向・内容を制御して、影響範囲を明示的に限定する構造

疎結合は以下のような文脈で登場します:

  • インターフェースによる依存の抽象化
  • DI(Dependency Injection)による依存の注入
  • オブザーバパターンなどによる制御の間接化

Javaにおける疎結合の実践パターン

1. インターフェースで依存先を抽象化する

依存の抽象化
public interface MailSender {
    void send(String to, String message);
}

public class NotificationService {
    private final MailSender mailSender;

    public NotificationService(MailSender mailSender) {
        this.mailSender = mailSender;
    }

    public void notifyUser(String userId) {
        // ...
        mailSender.send(userId, "Hello");
    }
}
  • 依存先(MailSender)をインターフェースにし、実装は注入により決定
  • テストや拡張のための柔軟性が確保される

2. DIによるインスタンス制御

JavaではSpringなどのDIコンテナを通じて、実装の差し替えやモック化が可能になります。

@Bean
public MailSender mailSender() {
    return new SmtpMailSender();
}

DIによる疎結合は、構成ファイルや設定の柔軟性に依存しますが、コード上は明確に抽象化が維持される設計になります。

疎結合の「行き過ぎ」による設計ミス

1. 意味のないインターフェース化

無意味な抽象化例
public interface Logger {
    void log(String message);
}

public class DefaultLogger implements Logger {
    public void log(String message) {
        System.out.println(message);
    }
}

Loggerの実装が1つしかない、もしくは差し替える必要が全くない場合、抽象化による疎結合は“設計コストの増加”を招くだけになります。

疎結合は「設計目的」ではなく「実装手段」

将来的に変更・差し替えが必要な場合に備えて疎結合にする。
逆に言えば「差し替え予定がないなら疎結合である必要はない」こともあります。

2. 疎結合化の副作用:トレース性・責務の不明瞭化

インターフェースが乱立すると、呼び出し元と実装の関係が見えにくくなり、構造が不透明になります。

// どの実装が使われているか、IDE上でも追跡困難
Service service = container.resolve(Service.class);

テスト性や柔軟性は高まっても、日常の保守・デバッグにおけるトレースコストが増加する可能性も考慮すべきです。

レビュー観点:「疎結合であるべき理由があるか?」

チェックリスト

レビュー観点

疎結合の目的が「変更に強くするため」であるかを確認し、過剰抽象による構造の不透明化が起きていないかを重点的に見る。

設計補足:疎結合と「局所的最適化」

疎結合を層・単位・責務という文脈で設計するなら有効ですが、
個別のクラスレベルでむやみに導入すると、構造は複雑化しやすくなります。

適切なスコープでの疎結合が必要

  • サービスの呼び出し先だけでなく、呼び出し元との関係性を設計に含める
  • クラス内で完結する責務に対してまでインターフェースを導入しない
  • インターフェース化する責務の粒度を見誤らない

まとめ:「疎結合」は常に良い設計ではない

疎結合は、「柔軟性」「拡張性」「テスト容易性」を得る手段として非常に強力です。
しかし、以下の観点から過剰な抽象化には設計上の注意が必要です。

  • 疎結合にする目的が明確か?
  • その疎結合が実際に活用されているか?
  • 抽象化によって構造が逆に追いづらくなっていないか?

レビューアーは「疎結合にすべきか?」ではなく、
「その疎結合が何をもたらし、何を失っているか」を問う視点を持つべきです。