DP-10: Facade パターン
複数のサブシステムを組み合わせた複雑な処理を、シンプルな窓口(ファサード)の陰に隠蔽するパターンです。 呼び出し側はサブシステムの内部構造を知らなくても、窓口のメソッドを呼ぶだけで処理が完結します。
Facade パターンとは
「ファサード(Facade)」は建築用語で「建物の正面」を意味します。 建物の内部がどれだけ複雑な構造をしていても、外から見える正面はシンプルに整えられています。 Facade パターンも同様に、複数のサブシステムが連携する複雑な処理を、 シンプルなインターフェースの陰に隠してしまうパターンです。
主なユースケース
- ライブラリのラッパー: 外部ライブラリの複雑な API を自社のシンプルなクラスで包んで使いやすくする
- 複数 API の統合: 認証・テンプレート・SMTP・ログなど複数の機能をひとつの「メール送信」メソッドにまとめる
- レガシーシステムの隠蔽: 古いシステムの複雑な呼び出し手順を新しい Facade で包み、移行期間中もシンプルに使えるようにする
Java 標準ライブラリの実例: java.util.logging
Java の標準ログライブラリ(java.util.logging)は Facade パターンの実例です。 内部では Handler(出力先管理)・Formatter(フォーマット)・Filter(フィルタリング)が連携していますが、 利用者は Logger の info() や warning()だけ呼べばログを記録できます。
// Logger(Facade)を使うだけで、Handler/Formatter/Filter を意識しなくて良い
Logger logger = Logger.getLogger(MyApp.class.getName());
logger.info("処理が完了しました"); // ← これだけでOK
logger.warning("注意が必要です");サンプルコード
Java 8 版では各サブシステム(SmtpClient・TemplateEngine・AuditLogger)が独立したクラスとして定義されています。EmailFacade がそれらを組み合わせ、呼び出し側は sendWelcomeEmail() だけ知っていれば良い構造になっています。
よくあるミス・注意点
⚠️ Facade に全ロジックを詰め込んで「神クラス」になる
Facade は「窓口」であり、各処理の実装は必ずサブシステムに委譲(いじょう)すべきです。 「とりあえず Facade に書けばいい」と考えると、Facade クラスが何千行にも膨れ上がり、 メンテナンスが困難な「神クラス(God Class)」になってしまいます。 Facade はあくまでも呼び出しの調整役に留め、ビジネスロジックは適切なサブシステムに置きましょう。
⚠️ サブシステムへの直接アクセスを禁止してしまう
Facade はあくまで「便利な窓口」であり、サブシステムを隠す「壁」ではありません。 高度な使い方をしたい利用者がサブシステムに直接アクセスできる余地を残しておきましょう。 例えば、SmtpClient をpackage-private にして外から使えなくすると、 細かい制御が必要なケースに対応できなくなります。
⚠️ Adapter パターンと混同する
Adapter パターンは「互換性のないインターフェース同士をつなぐ」ためのパターンで、 主に1対1の変換を行います。 Facade パターンは「複数のサブシステムをまとめてシンプルな窓口を作る」ためのパターンです。 「既存インターフェースに合わせる → Adapter」「複雑な処理をまとめる → Facade」と覚えましょう。
テストする観点
- 各サブシステム(SmtpClient・TemplateEngine・AuditLogger)が独立してテストできること
- Facade が各サブシステムへ正しく委譲していること(sendWelcomeEmail を呼んだとき SmtpClient.send が呼ばれるか)
- テンプレートのプレースホルダーが正しく置換されること(
{{userName}}が実際の名前に変わるか) - 送信中に例外が発生したとき、AuditLogger にエラーログが記録され、例外が再スローされること
- Java 17 版: EmailConfig record のアクセサ(host()・user()・password())が正しい値を返すこと
- Java 21 版: EmailRequest の各サブタイプ(Welcome・Password・Notification)に対して正しい件名・本文が生成されること