ソフトウェア設計

SwiftのFacadeパターン:複雑なサブシステムを1つのメソッドに隠す

Facadeパターンは、複数のオブジェクトが絡み合うサブシステムに、シンプルな単一の入り口を提供します。Swiftの会員登録を例に、呼び出し順を一か所に集約する方法と、Adapter・Proxy・Decoratorとの違いを解説します。

読了 5 分
SwiftのFacadeパターン:複雑なサブシステムを1つのメソッドに隠すのカバー画像

先日、会員登録のロジックを見直していて、思わずため息が出ました。

ボタンを1回押しただけなのに、View Controllerからバリデーション、ネットワーク リクエスト、トークン保存、通知登録など、6〜7個のオブジェクトを直接呼び出していたのです。

別の画面でも使う必要がありましたが、その順序と組み合わせを丸ごとコピーしたくはありませんでした。

そんなときに使うのが、SwiftのFacadeパターンです。

結論から言うと、Facadeパターンは複数のオブジェクトが絡む複雑なサブシステムを、signUp()のような1つのメソッドで包む構造です。利用側は内部の動きを知る必要がありません。

インターフェース変換・アクセス制御・機能追加の境界は、Adapter・Facade・Proxy・Decoratorの比較で一目で確認できます。

今日はSwiftコードでこのパターンをどう適用するか、いつ使うとよく、いつ逆効果になるのかまで、私の経験を交えて説明します。

Facadeパターンとは?

Facadeは、もともと建物の「正面外観」を意味する言葉です。

外からは整った正面だけが見えますが、中には配管や電線など、複雑な設備が詰まっています。

ソフトウェアも同じです。

内部で複数のクラスが互いを呼び出して動くサブシステムがあるとき、その前に1つの窓口を置きます。

呼び出し側は、その窓口にだけ話しかければ済みます。

核心は「単純化された入り口」です。

Facadeは複雑さをなくすのではなく、1か所に閉じ込め、外側には簡単なドアを1つだけ開けるパターンです。

内部実装をなくすのではなく、隠す点が重要です。

配管はそのまま存在し、壁の裏に隠れているだけです。


Swiftで実装するとこうなります

言葉だけではイメージしにくいので、コードを見てみましょう。

会員登録の流れに、バリデーション、サーバー登録、トークン保存という3つのサブシステムがあるとします。

まずは隠したい内部オブジェクトです。

struct Validator { func check(_ email: String) -> Bool { email.contains("@") } }
struct AuthAPI { func register(_ email: String) -> String { "token_\(email)" } }
struct TokenStore { func save(_ token: String) { /* キーチェーン保存 */ } }

この3つをView Controllerが直接呼び出すと、コードが散らかります。

そこでFacadeが代わりに連携させます。

struct SignUpFacade {
    private let validator = Validator()
    private let api = AuthAPI()
    private let store = TokenStore()

    func signUp(email: String) -> Bool {
        guard validator.check(email) else { return false }
        let token = api.register(email)   // 内部の順序はここだけで管理
        store.save(token)
        return true
    }
}

これで利用側は、たった1行で済みます。

このように、SignUpFacade().signUp(email: "[email protected]")です。

呼び出し側は、先にバリデーションを行い、その後にトークンを保存する順序を知る必要がありません。

1つのFacadeが3つのサブシステムを代わりに調整する図
1つのFacadeが3つのサブシステムを代わりに調整する図

後から順序が変わったり手順が増えたりしても、Facadeの内部だけを修正すれば済みます。


いつ使うべきで、いつ避けるべきか?

実際に使ってみて感じた判断基準をまとめました。

Facadeが向いている場面

  • 複数のオブジェクトを決まった順序で毎回同じように呼び出すコードが、あちこちで繰り返されるとき
  • 外部ライブラリや複雑なSDKを包み、アプリに合ったわかりやすい名前に変えたいとき
  • View Controllerが知りすぎていて、責務を減らしたいとき

むしろ避けたほうがよい場面

  • サブシステムがもともと単純で、隠すものがほとんどないとき(不要な層が1つ増えるだけです)
  • 毎回細かな制御が必要で、結局Facadeを通り越して内部を直接呼ぶことになるとき

ここで1つ、押さえておきたいことがあります。

Facadeは内部へのアクセスを「遮断」するものではありません。

簡単な道を1つ開くだけで、必要なら内部オブジェクトを直接使っても構いません。

そのため、すべてのアクセスを制御する他のパターンとは性質が異なります。


よくある疑問をいくつか

Q. Facadeと単なるユーティリティ関数は何が違いますか?

ユーティリティ関数は通常、独立した1つの機能を担います。一方、Facadeは複数オブジェクトの協調と順序を調整します。

「何を隠すか」が違います。

Q. プロトコルにする必要がありますか?

必ずしも必要ではありません。

ただしテストでFacadeをモックに置き換えたいなら、プロトコルとして抽象化しておくと、はるかに便利です。

Q. Adapterパターンと混同します。

Adapterは合わないインターフェースを適合させることが目的で、Facadeは複雑なものを単純に見せることが目的です。

目的が違うと覚えるとわかりやすいでしょう。

このサンプルコードは、実際のプロジェクトでこのように整理しました
このサンプルコードは、実際のプロジェクトでこのように整理しました

まとめ

複雑な呼び出しのまとまりを見るたびに、「これを1つのメソッドに包めないか?」と自問してみてください。

その問いだけで、コードがぐっと読みやすくなることがよくあります。

Facadeは華やかなパターンではありませんが、実務で最も頻繁に頼りになる堅実なツールです。

まずは今日の会員登録例から、気軽に試してみてください。

きれいなドアを1つだけ開ければよい、まさにこの感覚です
きれいなドアを1つだけ開ければよい、まさにこの感覚です

あわせて読みたい