DP-07: Bridge パターン
抽象化と実装を別の継承ツリーに分離し、それぞれを独立して変更・拡張できるパターンです。 「通知の種類(緊急・レポート)」と「送信手段(メール・SMS)」を独立させることで、 両者の組み合わせを自由に扱えます。
Bridge パターンとは
Bridge(ブリッジ)パターンは、クラスを「抽象(何をするか)」と「実装(どうやるか)」の 2つの独立した継承ツリーに分けるパターンです。 抽象クラスが実装インターフェースへの参照を持ち(ブリッジ)、実行時に差し替えられます。
Bridge パターンが役立つ場面
- 多次元の変化: 「通知種別 × 送信手段」のように2軸で変化するとき、単純な継承だと組み合わせ爆発する
- 実装の差し替え: メール送信をSMS送信に変えるなど、実行時に実装を切り替えたい場面
- 独立した拡張: 通知種別と送信手段を別々のチームが独立して拡張・変更できる
継承による問題と Bridge の解決策
継承だけで「緊急メール通知」「緊急SMS通知」「レポートメール通知」「レポートSMS通知」を 実装すると4クラス必要です。通知種別が3種・送信手段が4種になると 3×4=12 クラスが必要になります。
Bridge パターンでは通知種別クラス(抽象側)+ 送信手段クラス(実装側)を組み合わせるだけなので、 3+4=7 クラスで済みます。
サンプルコード
Java 8 では interface(Implementor)と abstract class(Abstraction)を組み合わせて Bridge パターンを実装します。Abstraction は Implementor への参照をフィールドに持ち(ブリッジ)、コンストラクタで受け取ることで実行時に差し替えられます。
よくあるミス・注意点
⚠️ Adapter パターンと混同してしまう
Adapter パターンは「既存のインターフェースを別のインターフェースに変換する」パターンです。 Bridge パターンは「設計の最初から抽象と実装を分離する」パターンです。 Adapter は後付けの変換、Bridge は最初から意図した分離、という違いがあります。
⚠️ 抽象クラスで実装(Implementor)を直接インスタンス化してしまう
抽象クラス内で new EmailSender() のように 具体実装クラスを直接作ると、Bridge の恩恵がなくなります。 実装はコンストラクタの引数で外から渡す(依存性の注入)ことで、柔軟な差し替えが可能になります。
⚠️ 変化の軸が1つしかない場面で使うと過設計になる
Bridge パターンは「2つの独立した変化軸がある」場合に効果を発揮します。 通知の種類が1種類しかない、または送信手段が1つだけなら、 単純なクラス継承や Strategy パターンのほうがシンプルな場合があります。 パターンの適用は「将来の拡張性」を見据えて判断しましょう。
テストする観点
- UrgentNotification に EmailSender を渡したとき、件名に「【緊急】」が含まれること
- UrgentNotification に SmsSender を渡したとき、同じメッセージが SMS 形式で送信されること(送信手段のみ変化)
- ReportNotification に EmailSender を渡したとき、件名が「定期レポート」であること
- 同じ EmailSender インスタンスを UrgentNotification と ReportNotification で共有しても、それぞれ独立して動作すること
- recipient に空文字を渡してもエラーにならないこと(境界値)
- message に null を渡したとき NullPointerException が発生しないこと(境界値)