ソフトウェア設計

Mediator vs Observer vs Facade 完全比較:オブジェクト通信パターン3選

Mediatorは複雑に絡み合ったオブジェクトの関係を中央で調整し、Observerは状態変化を一対多で通知し、Facadeは複雑な内部をシンプルな窓口で包みます。3つの違いと選び方をSwiftの例で比較します。

読了 6 分
Mediator vs Observer vs Facade 完全比較:オブジェクト通信パターン3選のカバー画像

オブジェクトが増えるほど、コードがスパゲッティ化する瞬間が訪れます。1つの画面でView Controller、ネットワーク、キャッシュ、ロガーが互いを直接呼び始めると、どこを直しても別の場所が壊れます。

そんなとき候補になるのがMediator、Observer、Facadeの3つです。どれも「オブジェクト通信を整理する」と紹介されますが、実際に解決する問題はそれぞれ異なります。

Mediatorは絡み合った関係を中央で制御し、Observerは状態変化を一対多の通知として扱い、Facadeは複雑な内部をシンプルな窓口にまとめます。

この一文だけ覚えておけば、半分は終わりです。ここから、それぞれをいつ使うのか、どう違うのかをコードとともに説明します。


3つのパターンを一言でまとめると

混乱したときに見返せるよう、まず要点を整理します。

  1. Mediator — 複数のオブジェクトが互いを直接参照せず、1つの仲介者を介して通信する
  2. Observer — 1つのオブジェクトの状態が変わると、購読している複数のオブジェクトに自動通知する
  3. Facade — 複雑なサブシステムの前にシンプルなインターフェースを置いて隠蔽する

同じ「通信の整理」でも、性質は異なります。

Mediatorは関係の複雑さを減らし、Observerは変化の伝播を扱い、Facadeは利用の複雑さを下げます。


MediatorとObserver、何が違うのか

この2つは特に混同されます。どちらもオブジェクト同士が直接呼び出し合うのを防ぐからです。

違いは関係の方向です。

Observerには明確な方向があります。1つのSubjectが変化すると、購読者へ一方向に流れます。チャットルームに新しいメッセージが届くと、画面、通知バッジ、音がそれぞれ反応するイメージです。

Mediatorでは方向が絡み合います。ボタンを押すとテキストフィールドが有効になり、それが保存ボタンの状態を変える、といった具合です。この多対多の関係を仲介者が代わりに調整します。

// Observer:状態変化が一方向に伝播
protocol Observer: AnyObject { func update(_ count: Int) }

final class Cart {
    private var observers: [Observer] = []
    var items = 0 { didSet { observers.forEach { $0.update(items) } } }
    func subscribe(_ o: Observer) { observers.append(o) }
}

final class Badge: Observer {
    func update(_ count: Int) { print("カートバッジ: \(count)") }
}

let cart = Cart()
cart.subscribe(Badge())
cart.items = 3
// 出力:カートバッジ: 3

カートが変わると、バッジも自動的に追従します。CartはBadgeが何かを知る必要がありません。

一方、Mediatorはオブジェクト間のルールを仲介者が保持します。

// Mediator:絡み合ったルールを仲介者が管理
final class FormMediator {
    var isAgreed = false
    func agreedChanged(_ value: Bool, submit: Button) {
        isAgreed = value
        submit.isEnabled = value   // ルール:同意すると送信を有効化
    }
}

final class Button { var isEnabled = false }

let submit = Button()
let mediator = FormMediator()
mediator.agreedChanged(true, submit: submit)
print(submit.isEnabled)
// 出力: true

チェックボックスとボタンが互いを直接知らなくても、仲介者が「同意したら送信を有効にする」というルールを守ります。

Mediatorの双方向調整とObserverの一方向通知を対比した図
左は絡み合った関係の調整、右は一方向の通知で、性質が異なります

Facadeは少し性質が異なる

Facadeは前の2つとは目的そのものが異なります。通信を調整するのではなく、複雑な内部を見えないように包むパターンです。

1つの注文を処理するために、決済、在庫、配送、通知モジュールを順番に呼び出す必要があるとします。呼び出し側のコードはすぐに煩雑になります。

Facadeはこれらを1つの窓口にまとめます。

final class OrderFacade {
    func placeOrder(_ id: String) {
        Payment().charge(id)
        Stock().reduce(id)
        Delivery().book(id)
        print("注文完了: \(id)")
    }
}

OrderFacade().placeOrder("A-1024")
// 出力:注文完了: A-1024

外側からはplaceOrderを1回呼ぶだけで終わります。内部にいくつモジュールがあっても知る必要はありません。

要点はここです。Facadeはオブジェクト同士を通信させるのではなく、呼び出し側と複雑なシステムの間を単純化します。方向は内側を向きます。


ひと目で比較

2026年現在、実務での私の分類を表にまとめました。

区分 Mediator Observer Facade
解決する問題 絡み合った多対多の関係 状態変化の伝播 複雑な内部の隠蔽
関係の方向 相互に絡む(中央調整) 一対多(一方向) 呼び出し側→システム
結合度の変化 オブジェクト間の結合を低減 主体と購読者を分離 利用の複雑さを低減
代表例 フォーム検証、チャットルームの調整 通知、データバインディング 決済・注文統合API

表にすると、3つが重ならないことがよく分かります。


いつ使い、いつ避けるべきか

パターンは乱用するとかえって害になります。絡み合った関係をすべてMediatorにまとめると、仲介者がGod objectになりやすいからです。

  • Mediator — 3〜4個以上のオブジェクトが互いを直接参照し、ルールが絡み合っているとき。ただしルールが単純なら仲介者が肥大化するため避けます。
  • Observer — 1か所の変化を複数の場所が知る必要があるとき。購読解除を忘れるとメモリーリークが起きるので注意してください。
  • Facade — 複雑な呼び出し手順を隠したいとき。内部を細かく制御する必要がある場所では、かえって邪魔になります。

一言でいえば、関係が絡むならMediator、変化を知らせるならObserver、手順を隠すならFacadeです。

FACADEの付箋が貼られたモニターにSwiftコードが開かれている机
結局、コードがどれだけきれいになるかがパターン選びの基準でした

面接ではこう聞かれます

Q. MediatorとObserverの違いは何ですか?

Observerは、Subjectの状態変化が購読者へ一方向に伝播する一対多の構造です。一方Mediatorは、絡み合ったオブジェクト間の相互作用ルールを仲介者が中央で調整する多対多の構造です。方向性と関係の複雑さが主な違いです。

Q. Facadeも結合度を下げますが、Mediatorとはどう違いますか?

Facadeはサブシステムの前にシンプルなインターフェースを置き、呼び出し側とシステム間の利用の複雑さを下げます。一方Mediatorは、同僚オブジェクト間の相互通信を調整します。「Facadeは一方向の単純化、Mediatorは相互作用の調整」と答えるとよいでしょう。


3つのパターンを暗記するより、今のコードが「関係が絡む問題」なのか、「変化を伝播する問題」なのか、「手順が複雑な問題」なのかを先に考えてください。答えが決まれば、パターンは自然に決まります。今日のリファクタリングで1つだけ選んで適用してみましょう。

あわせて読みたい