前回の振り返り
前回は、Adapterパターンだけでは解決できない課題を整理しました。呼び出し側にAdapter管理の責任が残り、フォールバック処理を毎回実装する必要がありました。
今回は、この問題を「Facadeパターン」で解決します。
今回の目標
第5回となる今回は、Facadeパターンを使って複数のAdapterを統合管理します。呼び出し側は「天気を取得」と言うだけでOK。内部で自動フォールバックする仕組みを実装します。
Facadeパターンとは
Facadeパターンは、複雑なサブシステムに対してシンプルなインターフェースを提供するデザインパターンです。
「Facade」はフランス語で「建物の正面」を意味します。建物の裏側がどんなに複雑でも、正面から見れば美しい一枚の壁に見える。利用者は建物の内部構造を知る必要がありません。
日常生活での例
ホテルのコンシェルジュを想像してください。
- 「レストランを予約して」と言えば、コンシェルジュが複数のレストランを調べ、空き状況を確認し、予約を取ってくれます
- 利用者は「どのレストランがあるか」「電話番号は何か」「予約方法は何か」を知る必要がありません
- コンシェルジュ = Facade
WeatherFacadeの設計
WeatherFacadeは以下の責務を持ちます。
- 複数のAdapterを内部で管理する
- 天気情報の取得リクエストを受け付ける
- 順番にAdapterを試し、成功したら結果を返す(フォールバック)
- すべて失敗した場合はundefを返す
クラス図
classDiagram
class WeatherFacade {
-adapters: Array
+new(adapters)
+get_weather(city)
}
class WeatherAdapter::Role {
<<interface>>
+get_weather(city)*
+name*
+show_weather(city)
}
class WeatherAdapter::OpenWeatherMap {
+name
+get_weather(city)
}
class WeatherAdapter::WeatherStack {
+name
+get_weather(city)
}
WeatherFacade --> WeatherAdapter::Role : uses
WeatherAdapter::OpenWeatherMap ..|> WeatherAdapter::Role
WeatherAdapter::WeatherStack ..|> WeatherAdapter::Role
WeatherFacadeの基本実装
まず、WeatherFacadeの基本構造を実装します。
| |
たったこれだけです。シンプルな設計がFacadeの特徴です。
動作の流れ
get_weatherが呼ばれると、adapters配列を順番に走査- 各Adapterの
get_weatherを呼び出し - 成功(truthy な値が返る)したら、その結果を返して終了
- 失敗(undefやfalseが返る)したら、次のAdapterを試す
- すべて失敗したらundefを返す
フォールバック機能の動作確認
実際にフォールバックが動作することを確認しましょう。
| |
実行結果:
| |
注目すべき点:
- Tokyo: OpenWeatherMapから取得(最初に成功)
- Osaka: OpenWeatherMapから取得(最初に成功)
- Sapporo: OpenWeatherMapになかったので、WeatherStackから取得(フォールバック成功)
- Fukuoka: どちらにもなかったので失敗
Facadeの威力: 呼び出し側の変化
Facade導入前と導入後で、呼び出し側のコードを比較してみましょう。
Before(Facadeなし)
| |
After(Facadeあり)
| |
呼び出し側の責任が大幅に軽減されました。
どのAPIから取得したか記録する
デバッグやログ出力のために、どのAPIから取得したかを記録する機能を追加しましょう。先ほどのコードでは、戻り値にsourceフィールドを追加していました。
| |
これにより、フォールバックが発生したことを確認できます。
完成コード
すべてをまとめた完成コードです。
| |
実行結果:
| |
Facadeパターンのメリット
1. シンプルなインターフェース
利用者はWeatherFacadeだけを知っていれば良い。内部にどれだけのAdapterがあるかは気にする必要がありません。
2. 疎結合
呼び出し側とAdapter群が疎結合になります。Adapterの追加・削除がFacade内部で完結します。
3. 関心の分離
- Adapter: 各APIの違いを吸収
- Facade: 複数のAdapterを統合管理
- 呼び出し側: 天気情報を使うだけ
それぞれの責任が明確に分離されています。
委譲(Delegation)について
Facadeパターンでは「委譲」という技術を使っています。
| |
Facadeは自分で天気データを持っているわけではありません。Adapterに処理を「委譲」して、結果を受け取っているだけです。
これにより:
- Facadeは「何を持っているか」ではなく「誰に頼むか」だけを管理
- 新しいAdapterの追加が容易
- テスト時にモックAdapterを注入可能
まとめ
今回は、Facadeパターンを使って複数のAdapterを統合管理しました。
- WeatherFacadeクラスで複数のAdapterを一元管理
- フォールバック機能により、失敗時に自動で次のAPIを試行
- 呼び出し側は「天気を取得」とだけ言えばOK
- 委譲を使って処理をAdapterに任せる
コードがさらにスッキリしました。
次回予告
基本的な機能は完成しましたが、まだ改善の余地があります。同じ都市の天気を何度も問い合わせるのは無駄です。次回は、キャッシュ機能を追加して、パフォーマンスを向上させます。お楽しみに!
