#10 / 23
S構造DIFF
ファサード
Facade
ホテルのコンシェルジュ。中で誰がどう動いてるかは知らなくていい、頼むのは『窓口の1人』だけ。
Intent · 目的
複雑なサブシステム群への『簡単な窓口』を提供する。クライアントは中身の細かいクラスを知らずに、ファサード1つを呼べば目的を達成できるようになる。
Motivation · 動機
ホテルで「空港まで行きたい」と思った時。タクシー会社に電話して、配車時間を確認して、料金を確認して、行き先を伝えて……は面倒。コンシェルジュに『空港までお願いします』と言うだけで全部やってくれるのが理想。プログラムでも同じ。「メールを送る」のために SMTP接続→ヘッダ生成→MIMEエンコード→再送制御 を全部利用側に書かせるのは酷。`Mailer.send(to, body)` 1行で済む窓口を1個作れば、利用側はシンプルにでき、内部の実装も差し替えやすくなる。
適用場面
- 1サブシステムの利用が複雑で、典型的な利用手順をまとめたい場合(メール送信、決済処理)。
- 2クライアントとサブシステムの結合を緩めたい場合(後で内部を差し替えたい)。
- 3サブシステムを段階的に置き換えていきたい場合 ── ファサードを境界線にする。
概念図
サンプルコード
class SmtpClient { connect(){} send(raw: string){ console.log("send:", raw); } }
class MimeEncoder { encode(body: string){ return `MIME(${body})`; } }
class HeaderBuilder { build(to: string){ return `To: ${to}\n`; } }
class Mailer {
private smtp = new SmtpClient();
private enc = new MimeEncoder();
private hb = new HeaderBuilder();
send(to: string, body: string){
this.smtp.connect();
const raw = this.hb.build(to) + this.enc.encode(body);
this.smtp.send(raw);
}
}
new Mailer().send("a@example.com", "Hello");Pros · メリット
- +クライアントから見た複雑度を一気に下げられる。20個の API が1個の窓口に圧縮される。
- +サブシステムの結合を緩め、内部実装の差し替えがやりやすい。
- +ライブラリ作者にとっては『推奨ユースケース』を体系化する場所にもなる。
Cons · デメリット
- −便利だからと何でも詰め込むと、ファサードが神クラス化する。『Mailer に支払い処理が…?』
- −細粒度な制御をしたい場面ではファサード越しでは届かないことがある。
- −下層が変わると、ファサードの API は据え置きでも内部修正の頻度は上がる。
関連パターン
⚔ ready to test
理解度を確かめる時間だ
3 問のクイズで、 このパターンを身体に染み込ませよう。