オブジェクトが増えるほど、コードがスパゲッティ化する瞬間が訪れます。1つの画面でView Controller、ネットワーク、キャッシュ、ロガーが互いを直接呼び始めると、どこを直しても別の場所が壊れます。
そんなとき候補になるのがMediator、Observer、Facadeの3つです。どれも「オブジェクト通信を整理する」と紹介されますが、実際に解決する問題はそれぞれ異なります。
Mediatorは絡み合った関係を中央で制御し、Observerは状態変化を一対多の通知として扱い、Facadeは複雑な内部をシンプルな窓口にまとめます。
この一文だけ覚えておけば、半分は終わりです。ここから、それぞれをいつ使うのか、どう違うのかをコードとともに説明します。
3つのパターンを一言でまとめると
混乱したときに見返せるよう、まず要点を整理します。
- Mediator — 複数のオブジェクトが互いを直接参照せず、1つの仲介者を介して通信する
- Observer — 1つのオブジェクトの状態が変わると、購読している複数のオブジェクトに自動通知する
- 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
チェックボックスとボタンが互いを直接知らなくても、仲介者が「同意したら送信を有効にする」というルールを守ります。
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です。
面接ではこう聞かれます
Q. MediatorとObserverの違いは何ですか?
Observerは、Subjectの状態変化が購読者へ一方向に伝播する一対多の構造です。一方Mediatorは、絡み合ったオブジェクト間の相互作用ルールを仲介者が中央で調整する多対多の構造です。方向性と関係の複雑さが主な違いです。
Q. Facadeも結合度を下げますが、Mediatorとはどう違いますか?
Facadeはサブシステムの前にシンプルなインターフェースを置き、呼び出し側とシステム間の利用の複雑さを下げます。一方Mediatorは、同僚オブジェクト間の相互通信を調整します。「Facadeは一方向の単純化、Mediatorは相互作用の調整」と答えるとよいでしょう。
3つのパターンを暗記するより、今のコードが「関係が絡む問題」なのか、「変化を伝播する問題」なのか、「手順が複雑な問題」なのかを先に考えてください。答えが決まれば、パターンは自然に決まります。今日のリファクタリングで1つだけ選んで適用してみましょう。

